最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS新增繪制圓的方法實(shí)例代碼

 更新時(shí)間:2020年05月18日 08:42:19   作者:CobableKun  
這篇文章主要給大家介紹了關(guān)于iOS新增繪制圓的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

iOS 的坐標(biāo)系和我們幾何課本中的二維坐標(biāo)系并不一樣!

# BezierPath繪制圓弧

使用 UIBezierPath 進(jìn)行繪制圓弧的方法,通常會(huì)直接使用 addArc :

addArc(withCenter:, radius:, startAngle:, endAngle:, clockwise:)

或者使用 addCurve 進(jìn)行擬圓弧:

addCurve(to:, controlPoint1:, controlPoint2:)

其實(shí)我們可以通過,兩個(gè)坐標(biāo)點(diǎn)(startPoint & endPoint),和兩點(diǎn)間的線段對(duì)應(yīng)的圓弧的弧度(angle/radian)就能確定這個(gè)圓的信息(半徑radius, center), 所以我們是不是可以封裝出只提供 start, end 和 angle 就能繪制 arc 的函數(shù)?

addArc(startPoint: , endPoint: , angle: , clockwise:)

# 計(jì)算兩點(diǎn)間的距離

這里邏輯很簡單不做贅述。

func calculateLineLength(_ point1: CGPoint, _ point2: CGPoint) -> CGFloat {
  let w = point1.x - point2.x
  let h = point1.y - point2.y
  return sqrt(w * w + h * h)
}

# 計(jì)算兩點(diǎn)間的夾角

計(jì)算 point 和 origin 連線在 iOS 坐標(biāo)系的角度

func calculateAngle(point: CGPoint, origin: CGPoint) -> Double {
  
  if point.y == origin.y {
    return point.x > origin.x ? 0.0 : -Double.pi
  }
  
  if point.x == origin.x {
    return point.y > origin.y ? Double.pi * 0.5 : Double.pi * -0.5
  }
  // Note: 修正標(biāo)準(zhǔn)坐標(biāo)系角度到 iOS 坐標(biāo)系
  let rotationAdjustment = Double.pi * 0.5
  
  let offsetX = point.x - origin.x
  let offsetY = point.y - origin.y
  // Note: 使用 -offsetY 是因?yàn)?iOS 坐標(biāo)系與標(biāo)準(zhǔn)坐標(biāo)系的區(qū)別
  if offsetY > 0 {
    return Double(atan(offsetX / -offsetY)) + rotationAdjustment
  } else {
    return Double(atan(offsetX / -offsetY)) - rotationAdjustment
  }
}

# 計(jì)算圓心的坐標(biāo)

如果你已經(jīng)將幾何知識(shí)丟的差不多了的話,我在這里畫了個(gè)大概的草圖,如下( angle 比較小時(shí)):

angle 比較大時(shí):

所以我么可以寫出如下計(jì)算中心點(diǎn)的代碼

// Woring: 只計(jì)算從start到end **順時(shí)針** 計(jì)算對(duì)應(yīng)的 **小于π** 圓弧對(duì)應(yīng)的圓心
// Note: 計(jì)算逆時(shí)針(end到start)可以看做將傳入的start和end對(duì)調(diào)后計(jì)算順時(shí)針時(shí)的圓心位置
// Note: 計(jì)算大于π的叫相當(dāng)于將end和start對(duì)換后計(jì)算2π-angle的順時(shí)針圓心位置
// Note: 綜上傳入start,end,angle 右外部自行處理邏輯
func calculateCenterFor(startPoint start: CGPoint, endPoint end: CGPoint, radian: Double) -> CGPoint {
  guard radian <= Double.pi else {
    fatalError("Does not support radian calculations greater than π!")
  }
  
  guard start != end else {
    fatalError("Start position and end position cannot be equal!")
  }
  
  if radian == Double.pi {
    let centerX = (end.x - start.x) * 0.5 + start.x
    let centerY = (end.y - start.y) * 0.5 + start.y
    return CGPoint(x: centerX, y: centerY)
  }
  
  let lineAB = calculateLineLength(start, end)
  
  // 平行 Y 軸
  if start.x == end.x {
    let centerY = (end.y - start.y) * 0.5 + start.y
    let tanResult = CGFloat(tan(radian * 0.5))
    let offsetX = lineAB * 0.5 / tanResult
    let centerX = start.x + offsetX * (start.y > end.y ? 1.0 : -1.0)
    return CGPoint(x: centerX, y: centerY)
  }
  
  // 平行 X 軸
  if start.y == end.y {
    let centerX = (end.x - start.x) * 0.5 + start.x
    let tanResult = CGFloat(tan(radian * 0.5))
    let offsetY = lineAB * 0.5 / tanResult
    let centerY = start.y + offsetY * (start.x < end.x ? 1.0 : -1.0)
    return CGPoint(x: centerX, y: centerY)
  }
  
  // 普通情況
  
  // 計(jì)算半徑
  let radius = lineAB * 0.5 / CGFloat(sin(radian * 0.5))
  // 計(jì)算與 Y 軸的夾角
  let angleToYAxis = atan(abs(start.x - end.x) / abs(start.y - end.y))
  let cacluteAngle = CGFloat(Double.pi - radian) * 0.5 - angleToYAxis
  // 偏移量
  let offsetX = radius * sin(cacluteAngle)
  let offsetY = radius * cos(cacluteAngle)
  
  var centetX = end.x
  var centerY = end.y
  // 以 start 為原點(diǎn)判斷象限區(qū)間(iOS坐標(biāo)系)
  if end.x > start.x && end.y < start.y {
    // 第一象限
    centetX = end.x + offsetX
    centerY = end.y + offsetY
  } else if end.x > start.x && end.y > start.y {
    // 第二象限
    centetX = start.x - offsetX
    centerY = start.y + offsetY
  } else if end.x < start.x && end.y > start.y {
    // 第三象限
    centetX = end.x - offsetX
    centerY = end.y - offsetY
  } else if end.x < start.x && end.y < start.y {
    // 第四象限
    centetX = start.x + offsetX
    centerY = start.y - offsetY
  }
  
  return CGPoint(x: centetX, y: centerY)
}

這里附上一個(gè)逆時(shí)針繪制第一張圖中圓心位置的草圖,圖中已將 start 和 end 對(duì)換

如果你對(duì)其中計(jì)算時(shí)到底該使用 + 還是 - 有困惑的話也可以自己多畫些草圖大概驗(yàn)證下,總之有疑惑多動(dòng)手🤭

# 實(shí)現(xiàn)我們的目標(biāo)函數(shù)

在有了計(jì)算圓心位置,和兩點(diǎn)間角度的函數(shù)后我們很容易就能實(shí)現(xiàn) addArc(startPoint: , endPoint: , angle: , clockwise:) 了;

func addArc(startPoint start: CGPoint, endPoint end: CGPoint, angle: Double, clockwise: Bool) {
  
  guard start != end && (angle >= 0 && angle <= 2 * Double.pi) else {
    return
  }
  if angle == 0 {
    move(to: start)
    addLine(to: end)
    return
  }
  
  var tmpStart = start, tmpEnd = end, tmpAngle = angle
  // Note: 保證計(jì)算圓心時(shí)是從 start 到 end 順時(shí)針 小于 π 的角
  if tmpAngle > Double.pi {
    tmpAngle = 2 * Double.pi - tmpAngle
    (tmpStart, tmpEnd) = (tmpEnd, tmpStart)
  }
  if !clockwise {
    (tmpStart, tmpEnd) = (tmpEnd, tmpStart)
  }
  
  let center = calculateCenterFor(startPoint: tmpStart, endPoint: tmpEnd, radian: tmpAngle)
  let radius = calculateLineLength(start, center)
  
  var startAngle = calculateAngle(point: start, origin: center)
  var endAngle = calculateAngle(point: end, origin: center)
  // Note: 逆時(shí)針繪制則交換 startAngle 和 endAngle,并且將開始點(diǎn)移動(dòng)的 end 位置
  if !clockwise {
    (startAngle, endAngle) = (endAngle, startAngle)
    move(to: end)
  }
  
  addArc(withCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true)
  move(to: end)
}

# 完結(jié)

最后也不知道是你否會(huì)碰到相同的需求,這里附上源碼和一份樣例及運(yùn)行結(jié)果圖;

override func draw(_ rect: CGRect) {
  
  let path = UIBezierPath()
  var start = CGPoint(x: 160, y: 130)
  var end = CGPoint(x: 180, y: 200)
  path.move(to: start)
  path.addArc(startPoint: start, endPoint: end, angle: Double.pi * 1.6, clockwise: true)
  path.move(to: start)
  path.addArc(startPoint: start, endPoint: end, angle: Double.pi * 0.8, clockwise: true)
  
  start = CGPoint(x: 142, y: 130)
  end = CGPoint(x: 162, y: 200)
  path.move(to: start)
  path.addArc(startPoint: start, endPoint: end, angle: Double.pi * 0.4, clockwise: true)
  
  start = CGPoint(x: 140, y: 130)
  end = CGPoint(x: 160, y: 200)
  path.move(to: start)
  path.addArc(startPoint: start, endPoint: end, angle: Double.pi * 1.6, clockwise: false)
  path.move(to: start)
  path.addArc(startPoint: start, endPoint: end, angle: Double.pi * 0.8, clockwise: false)
  
  path.close()
  path.lineWidth = 1
  UIColor.red.setStroke()
  path.stroke()
}

ps: 每次都寫 Double.pi / x 很煩? 試試類似于 SwiftUI 提供的接口, 使用 度數(shù)(degress) 而非 弧度(radian)

struct Angle {
  private var degress: Double
  static func deggess(_ degress: Double) -> Angle {
    return .init(degress: degress)
  }
  // 弧度
  var radians: Double { Double.pi * degress / 180.0 }
}

// Angle.deggess(90).radians // 1.570796326794897
func addArc(startPoint start: CGPoint, endPoint end: CGPoint, angle: Angle, clockwise: Bool)

感謝閱讀,祝好祝順🥰

總結(jié)

到此這篇關(guān)于iOS新增繪制圓的文章就介紹到這了,更多相關(guān)iOS新增繪制圓內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IOS  手勢操作詳解及實(shí)例總結(jié)篇

    IOS 手勢操作詳解及實(shí)例總結(jié)篇

    這篇文章主要介紹了IOS 手勢操作詳解及實(shí)例總結(jié)篇的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • IOS開發(fā)環(huán)境windows化攻略

    IOS開發(fā)環(huán)境windows化攻略

    本人主要介紹了IOS開發(fā)環(huán)境windows化攻略,需要的朋友可以參考下
    2013-06-06
  • iOS開發(fā)之使用Storyboard預(yù)覽UI在不同屏幕上的運(yùn)行效果

    iOS開發(fā)之使用Storyboard預(yù)覽UI在不同屏幕上的運(yùn)行效果

    使用Storyboard做開發(fā)效率非常高,為了防止在團(tuán)隊(duì)中發(fā)生沖突,采取的解決辦法是負(fù)責(zé)UI開發(fā)的同事最好每人維護(hù)一個(gè)Storyboard, 公用的組件使用輕量級(jí)的xib或者純代碼來實(shí)現(xiàn),下面小編就給大家介紹如何使用Storyboard預(yù)覽UI在不同屏幕上的運(yùn)行效果,需要的朋友可以參考下
    2015-08-08
  • iOS提取APP中的圖片資源的方法

    iOS提取APP中的圖片資源的方法

    這篇文章主要介紹了iOS提取APP中的圖片資源的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • IOS中判斷卡頓的方案總結(jié)

    IOS中判斷卡頓的方案總結(jié)

    這篇文章主要介紹了IOS中判斷卡頓的方案總結(jié),對(duì)IOS性能感興趣的同學(xué),一定要看一下
    2021-04-04
  • IOS 開發(fā)之ObjectiveC的變量類型的字符代表

    IOS 開發(fā)之ObjectiveC的變量類型的字符代表

    這篇文章主要介紹了IOS 開發(fā)之ObjectiveC的變量類型的字符代表的相關(guān)資料,這里舉例說明如何使用Objective的變量類型的字符,幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下
    2017-08-08
  • iOS Moya實(shí)現(xiàn)OAuth請(qǐng)求的方法

    iOS Moya實(shí)現(xiàn)OAuth請(qǐng)求的方法

    這篇文章主要介紹了iOS Moya實(shí)現(xiàn)OAuth請(qǐng)求的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • 詳解Objective-C中的語法糖@{}究竟是什么

    詳解Objective-C中的語法糖@{}究竟是什么

    這篇文章主要給大家介紹了關(guān)于Objective-C中語法糖@{}究竟是什么的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • iOS 自定義狀態(tài)欄和導(dǎo)航欄詳細(xì)介紹

    iOS 自定義狀態(tài)欄和導(dǎo)航欄詳細(xì)介紹

    這篇文章主要介紹了iOS 自定義狀態(tài)欄和導(dǎo)航欄詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • IOS中Json解析實(shí)例方法詳解(四種方法)

    IOS中Json解析實(shí)例方法詳解(四種方法)

    本文將介紹TouchJson、 SBJson 、JSONKit 和 iOS5所支持的原生的json方法,解析國家氣象局API。通過本文給大家介紹IOS中Json解析的四種方法,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧
    2016-06-06

最新評(píng)論

周口市| 共和县| 南宁市| 陈巴尔虎旗| 湖口县| 宣武区| 鹿泉市| 临朐县| 喜德县| 平谷区| 满城县| 辛集市| 靖州| 台南市| 博湖县| 泽州县| 台东县| 阳城县| 刚察县| 丽江市| 安宁市| 定安县| 安远县| 阜城县| 普定县| 古丈县| 包头市| 金川县| 汾西县| 永平县| 泉州市| 朝阳市| 广南县| 饶河县| 南丹县| 清水河县| 津南区| 宜章县| 班玛县| 武陟县| 日土县|