CPDFSampleView.swift 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. //
  2. // CPDFSampleView.swift
  3. // ComPDFKit_Tools
  4. //
  5. // Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
  6. //
  7. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  8. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  9. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  10. // This notice may not be removed from this file.
  11. //
  12. import UIKit
  13. import ComPDFKit
  14. enum CPDFSamplesSelectedIndex: Int {
  15. case note = 0
  16. case highlight
  17. case underline
  18. case strikeout
  19. case squiggly
  20. case freehand
  21. case shapeCircle
  22. case shapeSquare
  23. case shapeArrow
  24. case shapeLine
  25. case freeText
  26. case signature
  27. case stamp
  28. case image
  29. case link
  30. case sound
  31. }
  32. enum CPDFArrowStyle: Int {
  33. case none = 0
  34. case openArrow = 1
  35. case closedArrow = 2
  36. case square = 3
  37. case circle = 4
  38. case diamond = 5
  39. }
  40. class CPDFSampleView: UIView {
  41. var selecIndex:CPDFSamplesSelectedIndex = .highlight
  42. var startArrowStyleIndex:CPDFArrowStyle = .none
  43. var endArrowStyleIndex:CPDFArrowStyle = .none
  44. var color:UIColor?
  45. var interiorColor:UIColor?
  46. var opcity:CGFloat = 0
  47. var thickness:CGFloat = 0
  48. var dotted:CGFloat = 0
  49. var familyName:String = "Helvetica"
  50. var styleName:String = ""
  51. var textAlignment:NSTextAlignment = .center
  52. var centerRect:CGRect = CGRect.zero
  53. var arrowRect:CGRect = CGRect.zero
  54. var textRect:CGRect = CGRect.zero
  55. var inkRect:CGRect = CGRect.zero
  56. override init(frame: CGRect) {
  57. super.init(frame: frame)
  58. }
  59. required init?(coder: NSCoder) {
  60. fatalError("init(coder:) has not been implemented")
  61. }
  62. override func layoutSubviews() {
  63. super.layoutSubviews()
  64. setNeedsDisplay()
  65. }
  66. override func draw(_ rect: CGRect) {
  67. super.draw(rect)
  68. guard let context = UIGraphicsGetCurrentContext() else { return }
  69. centerRect = rect.insetBy(dx: (bounds.size.width/20)*9, dy: (bounds.size.height/8)*3)
  70. let centerPoint = CGPoint(x: rect.midX, y: rect.midY)
  71. arrowRect = CGRect(x: centerPoint.x-bounds.size.height/4, y: centerPoint.y-bounds.size.height/4, width: bounds.size.height/2, height: bounds.size.height/2)
  72. textRect = rect.insetBy(dx: bounds.size.width/3+3, dy: bounds.size.height/3)
  73. inkRect = rect.insetBy(dx: bounds.size.width/4, dy: bounds.size.height/3)
  74. context.setFillColor(CPDFColorUtils.CAnnotationSampleDrawBackgoundColor().cgColor)
  75. context.fill(rect)
  76. drawSamples(context: context, rect: centerRect)
  77. }
  78. func drawSamples(context: CGContext, rect: CGRect) {
  79. switch selecIndex {
  80. case .note:
  81. context.setStrokeColor(red: 0, green: 0, blue: 0, alpha: 1.0)
  82. if let color = self.color {
  83. var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
  84. color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
  85. let updatedColor = UIColor(red: red, green: green, blue: blue, alpha: self.opcity)
  86. context.setFillColor(updatedColor.cgColor)
  87. } else {
  88. context.setStrokeColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
  89. context.setFillColor(UIColor.clear.cgColor)
  90. }
  91. // Draw outer boxes.
  92. let width: CGFloat = 1.0
  93. let size: CGFloat = rect.size.height / 5
  94. var outerRect1 = rect.insetBy(dx: 0, dy: 0)
  95. outerRect1.size.height -= size
  96. var outerRect2 = outerRect1
  97. outerRect2.origin.x += size
  98. outerRect2.origin.y += size*4
  99. outerRect2.size.width = size
  100. outerRect2.size.height = size
  101. context.setLineWidth(width)
  102. context.move(to: CGPoint(x: outerRect1.minX, y: outerRect1.minY))
  103. context.addLine(to: CGPoint(x: outerRect1.minX, y: outerRect1.maxY))
  104. context.addLine(to: CGPoint(x: outerRect2.minX, y: outerRect2.minY))
  105. context.addLine(to: CGPoint(x: outerRect2.midX, y: outerRect2.maxY))
  106. context.addLine(to: CGPoint(x: outerRect2.midX, y: outerRect2.minY))
  107. context.addLine(to: CGPoint(x: outerRect1.maxX, y: outerRect1.maxY))
  108. context.addLine(to: CGPoint(x: outerRect1.maxX, y: outerRect1.minY))
  109. context.closePath()
  110. context.drawPath(using: .fillStroke)
  111. // Draw inner lines.
  112. let count = 3
  113. let xDelta = rect.size.width / 10
  114. let yDelta = outerRect1.size.height / CGFloat(count + 1)
  115. var lineRect = outerRect1
  116. lineRect.origin.x += xDelta
  117. lineRect.size.width -= 2*xDelta
  118. for i in 0..<count {
  119. let y = lineRect.maxY - yDelta * CGFloat(i + 1)
  120. context.move(to: CGPoint(x: lineRect.minX, y: y))
  121. context.addLine(to: CGPoint(x: lineRect.maxX, y: y))
  122. context.strokePath()
  123. }
  124. case .highlight:
  125. let colorComponents = self.color?.cgColor.components
  126. let red = colorComponents?[0]
  127. let green = colorComponents?[1]
  128. let blue = colorComponents?[2]
  129. let fillColor = UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity).cgColor
  130. context.setFillColor(fillColor)
  131. context.fill(self.textRect)
  132. let sampleStr = "Sample"
  133. let font = UIFont.systemFont(ofSize: 27)
  134. let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.black]
  135. sampleStr.draw(in: self.textRect, withAttributes: attributes)
  136. case .underline:
  137. let sampleStr = "Sample"
  138. let colorComponents = self.color?.cgColor.components
  139. let red = colorComponents?[0]
  140. let green = colorComponents?[1]
  141. let blue = colorComponents?[2]
  142. let fillColor = UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity).cgColor
  143. context.setFillColor(fillColor)
  144. let strikeoutRect = self.textRect.insetBy(dx: 0, dy: (self.textRect.size.height/7) * 3)
  145. let underLineRect = strikeoutRect.offsetBy(dx: 0, dy: (self.textRect.size.height/7) * 3)
  146. context.fill(underLineRect)
  147. let font = UIFont.systemFont(ofSize: 27)
  148. let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.black]
  149. sampleStr.draw(in: self.textRect, withAttributes: attributes)
  150. case .strikeout:
  151. let sampleStr = "Sample"
  152. var red: CGFloat = 0
  153. var green: CGFloat = 0
  154. var blue: CGFloat = 0
  155. var alpha: CGFloat = 0
  156. self.color?.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
  157. let fillColor = UIColor(red: red, green: green, blue: blue, alpha: self.opcity).cgColor
  158. context.setFillColor(fillColor)
  159. let strikeoutRect = self.textRect.insetBy(dx: 0, dy: (self.textRect.size.height/7)*3)
  160. let underLineRect = strikeoutRect.offsetBy(dx: 0, dy: (self.textRect.size.height/7))
  161. context.fill(underLineRect)
  162. let font = UIFont.systemFont(ofSize: 27)
  163. let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.black]
  164. sampleStr.draw(in: self.textRect, withAttributes: attributes)
  165. case .squiggly:
  166. let sampleStr = "Sample"
  167. var red: CGFloat = 0
  168. var green: CGFloat = 0
  169. var blue: CGFloat = 0
  170. var alpha: CGFloat = 0
  171. self.color?.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
  172. context.setStrokeColor(UIColor(red: red, green: green, blue: blue, alpha: opcity).cgColor)
  173. let tWidth = self.textRect.size.width / 12.0
  174. context.move(to: CGPoint(x: self.textRect.minX, y: self.textRect.maxY))
  175. context.setLineWidth(2.0)
  176. context.addCurve(to: CGPoint(x: self.textRect.minX + tWidth, y: self.textRect.maxY + 5),
  177. control1: CGPoint(x: self.textRect.minX + tWidth * 2.0, y: self.textRect.maxY - 5),
  178. control2: CGPoint(x: self.textRect.minX + tWidth * 3.0, y: self.textRect.maxY))
  179. context.addCurve(to: CGPoint(x: self.textRect.minX + tWidth * 3.0, y: self.textRect.maxY),
  180. control1: CGPoint(x: self.textRect.minX + tWidth * 4.0, y: self.textRect.maxY + 5),
  181. control2: CGPoint(x: self.textRect.minX + tWidth * 5.0, y: self.textRect.maxY - 5))
  182. context.addCurve(to: CGPoint(x: self.textRect.minX + tWidth * 6.0, y: self.textRect.maxY),
  183. control1: CGPoint(x: self.textRect.minX + tWidth * 7.0, y: self.textRect.maxY + 5),
  184. control2: CGPoint(x: self.textRect.minX + tWidth * 8.0, y: self.textRect.maxY - 5))
  185. context.addCurve(to: CGPoint(x: self.textRect.minX + tWidth * 9.0, y: self.textRect.maxY),
  186. control1: CGPoint(x: self.textRect.minX + tWidth * 10.0, y: self.textRect.maxY + 5),
  187. control2: CGPoint(x: self.textRect.minX + tWidth * 11.0, y: self.textRect.maxY - 5))
  188. context.addCurve(to: CGPoint(x: self.textRect.minX + tWidth * 12.0, y: self.textRect.maxY),
  189. control1: CGPoint(x: self.textRect.minX + tWidth * 12.0, y: self.textRect.maxY),
  190. control2: CGPoint(x: self.textRect.minX + tWidth * 12.0, y: self.textRect.maxY))
  191. context.strokePath()
  192. let font = UIFont.systemFont(ofSize: 27)
  193. let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.black]
  194. sampleStr.draw(in: self.textRect, withAttributes: attributes)
  195. case .freehand:
  196. let colorComponents = self.color?.cgColor.components
  197. let red = colorComponents?[0]
  198. let green = colorComponents?[1]
  199. let blue = colorComponents?[2]
  200. let strokeColor = UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity).cgColor
  201. context.setStrokeColor(strokeColor)
  202. let tWidth = self.inkRect.size.width / 3.0
  203. context.move(to: CGPoint(x: self.inkRect.minX, y: self.inkRect.midY))
  204. context.setLineWidth(self.thickness)
  205. context.addCurve(to: CGPoint(x: self.inkRect.minX + tWidth * 3.0, y: self.inkRect.midY),
  206. control1: CGPoint(x: self.inkRect.minX + tWidth, y: self.inkRect.midY - 20),
  207. control2: CGPoint(x: self.inkRect.minX + tWidth * 2.0, y: self.inkRect.midY + 20))
  208. context.strokePath()
  209. case .shapeCircle:
  210. let colorComponents = self.color?.cgColor.components
  211. let red = colorComponents?[0]
  212. let green = colorComponents?[1]
  213. let blue = colorComponents?[2]
  214. let strokeColor = UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity).cgColor
  215. context.setStrokeColor(strokeColor)
  216. if self.interiorColor != UIColor.clear && self.interiorColor != nil {
  217. let interColorComponents = self.interiorColor?.cgColor.components
  218. let interRed = interColorComponents?[0]
  219. let interGreen = interColorComponents?[1]
  220. let interBlue = interColorComponents?[2]
  221. let fillColor = UIColor(red: interRed ?? 0, green: interGreen ?? 0, blue: interBlue ?? 0, alpha: self.opcity).cgColor
  222. context.setFillColor(fillColor)
  223. } else {
  224. context.setFillColor(UIColor.clear.cgColor)
  225. }
  226. let dashLengths: [CGFloat] = [6.0, self.dotted]
  227. context.setLineDash(phase: 0, lengths: dashLengths)
  228. context.setLineWidth(self.thickness)
  229. context.addArc(center: CGPoint(x: self.bounds.maxX/2, y: self.bounds.maxY/2), radius: 30, startAngle: 0, endAngle: 2 * .pi, clockwise: false)
  230. context.drawPath(using: .stroke)
  231. context.addArc(center: CGPoint(x: self.bounds.maxX/2, y: self.bounds.maxY/2), radius: 30, startAngle: 0, endAngle: 2 * .pi, clockwise: false)
  232. context.drawPath(using: .fill)
  233. case .shapeSquare:
  234. let colorComponents = self.color?.cgColor.components
  235. let red = colorComponents?[0]
  236. let green = colorComponents?[1]
  237. let blue = colorComponents?[2]
  238. let strokeColor = UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity).cgColor
  239. context.setStrokeColor(strokeColor)
  240. if self.interiorColor != UIColor.clear && self.interiorColor != nil {
  241. let interColorComponents = self.interiorColor?.cgColor.components
  242. let interRed = interColorComponents?[0]
  243. let interGreen = interColorComponents?[1]
  244. let interBlue = interColorComponents?[2]
  245. let fillColor = UIColor(red: interRed ?? 0, green: interGreen ?? 0, blue: interBlue ?? 0, alpha: self.opcity).cgColor
  246. context.setFillColor(fillColor)
  247. } else {
  248. context.setFillColor(UIColor.clear.cgColor)
  249. }
  250. context.setLineWidth(self.thickness)
  251. let dashLengths: [CGFloat] = [6.0, self.dotted]
  252. context.setLineDash(phase: 0, lengths: dashLengths)
  253. context.move(to: CGPoint(x: self.centerRect.minX, y: self.centerRect.minY))
  254. context.addLine(to: CGPoint(x: self.centerRect.maxX + 0.1, y: self.centerRect.minY))
  255. context.addLine(to: CGPoint(x: self.centerRect.maxX, y: self.centerRect.maxY))
  256. context.addLine(to: CGPoint(x: self.centerRect.minX, y: self.centerRect.maxY))
  257. context.addLine(to: CGPoint(x: self.centerRect.minX, y: self.centerRect.minY))
  258. context.addLine(to: CGPoint(x: self.centerRect.minX + 0.1, y: self.centerRect.minY))
  259. context.strokePath()
  260. context.fill(rect)
  261. case .shapeArrow:
  262. let colorComponents = self.color?.cgColor.components
  263. let red = colorComponents?[0]
  264. let green = colorComponents?[1]
  265. let blue = colorComponents?[2]
  266. context.saveGState()
  267. let strokeColor = (self.color?.withAlphaComponent(self.opcity) ?? .black).cgColor
  268. context.setStrokeColor(strokeColor)
  269. context.setLineWidth(self.thickness)
  270. context.setFillColor(strokeColor)
  271. var start = CGPoint(x: self.arrowRect.minX, y: self.arrowRect.maxY)
  272. var end = CGPoint(x: self.arrowRect.maxX, y: self.arrowRect.minY)
  273. end = drawEndArrow(context: context, startPoint: start, endPoint: end, style: endArrowStyleIndex)
  274. start = drawEndArrow(context: context, startPoint: end, endPoint: start, style: startArrowStyleIndex)
  275. let dashLengths: [CGFloat] = [6.0, self.dotted]
  276. context.setLineDash(phase: 0, lengths: dashLengths)
  277. context.move(to: start)
  278. context.addLine(to: end)
  279. context.setBlendMode(.normal)
  280. context.strokePath()
  281. context.restoreGState()
  282. case .shapeLine:
  283. let colorComponents = self.color?.cgColor.components
  284. let red = colorComponents?[0]
  285. let green = colorComponents?[1]
  286. let blue = colorComponents?[2]
  287. let strokeColor = UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity).cgColor
  288. context.setStrokeColor(strokeColor)
  289. context.setLineWidth(self.thickness)
  290. var start = CGPoint(x: self.arrowRect.minX, y: self.arrowRect.maxY)
  291. var end = CGPoint(x: self.arrowRect.maxX, y: self.arrowRect.minY)
  292. end = drawEndArrow(context: context, startPoint: start, endPoint: end, style: startArrowStyleIndex)
  293. start = drawEndArrow(context: context, startPoint: end, endPoint: start, style: endArrowStyleIndex)
  294. let dashLengths: [CGFloat] = [6.0, self.dotted]
  295. context.setLineDash(phase: 0, lengths: dashLengths)
  296. context.move(to: start)
  297. context.addLine(to: end)
  298. context.strokePath()
  299. case .freeText:
  300. let colorComponents = self.color?.cgColor.components
  301. let red = colorComponents?[0]
  302. let green = colorComponents?[1]
  303. let blue = colorComponents?[2]
  304. let cfont = CPDFFont(familyName: familyName, fontStyle: styleName)
  305. var font = UIFont.init(name: CPDFFont.convertAppleFont(cfont) ?? "Helvetica", size: thickness)
  306. if font == nil {
  307. font = UIFont(name: "Helvetica-Oblique", size: thickness)
  308. }
  309. let sampleStr = "Sample"
  310. if self.color == nil {
  311. self.color = UIColor.white
  312. }
  313. let attributedText = NSAttributedString(string: sampleStr, attributes: [NSAttributedString.Key.font: font!, NSAttributedString.Key.foregroundColor: UIColor(red: red ?? 0, green: green ?? 0, blue: blue ?? 0, alpha: self.opcity)])
  314. let textSize = attributedText.boundingRect(with: self.bounds.size, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).size
  315. var x: CGFloat = 0
  316. var y: CGFloat = 0
  317. switch self.textAlignment {
  318. case .left:
  319. x = self.bounds.origin.x
  320. y = self.bounds.origin.y + (self.bounds.size.height - textSize.height) / 2.0
  321. case .center:
  322. x = self.bounds.origin.x + (self.bounds.size.width - textSize.width) / 2.0
  323. y = self.bounds.origin.y + (self.bounds.size.height - textSize.height) / 2.0
  324. case .right:
  325. x = self.bounds.origin.x + (self.bounds.size.width - textSize.width)
  326. y = self.bounds.origin.y + (self.bounds.size.height - textSize.height) / 2.0
  327. default:
  328. x = self.bounds.origin.x + (self.bounds.size.width - textSize.width) / 2.0
  329. y = self.bounds.origin.y + (self.bounds.size.height - textSize.height) / 2.0
  330. }
  331. let center = CGPoint(x: x, y: y)
  332. attributedText.draw(at: center)
  333. default:break
  334. }
  335. }
  336. func drawEndArrow(context: CGContext, startPoint: CGPoint, endPoint: CGPoint, style: CPDFArrowStyle) -> CGPoint {
  337. var rpoint = endPoint
  338. switch style {
  339. case .openArrow:
  340. var points = [CGPoint](repeating: .zero, count: 3)
  341. rpoint = openArrowPoints(points: &points, point: endPoint, cpoint: startPoint)
  342. context.beginPath()
  343. context.addLines(between: points)
  344. context.setBlendMode(.normal)
  345. context.drawPath(using: .stroke)
  346. case .closedArrow:
  347. var points = [CGPoint](repeating: .zero, count: 3)
  348. rpoint = closedArrowPoints(points: &points, point: endPoint, cpoint: startPoint)
  349. context.beginPath()
  350. context.addLines(between: points)
  351. context.closePath()
  352. context.setBlendMode(.normal)
  353. context.drawPath(using: .stroke)
  354. case .square:
  355. var points = [CGPoint](repeating: .zero, count: 4)
  356. rpoint = squarePoints(points: &points, point: endPoint, cpoint: startPoint)
  357. context.beginPath()
  358. context.addLines(between: points)
  359. context.closePath()
  360. context.setBlendMode(.normal)
  361. context.drawPath(using: .stroke)
  362. case .circle:
  363. var points = [CGPoint](repeating: .zero, count: 1)
  364. rpoint = circlePoints(points: &points, point: endPoint, cpoint: startPoint)
  365. let radius = sqrt((rpoint.x - points[0].x) * (rpoint.x - points[0].x) + (rpoint.y - points[0].y) * (rpoint.y - points[0].y))
  366. context.beginPath()
  367. context.addArc(center: points[0], radius: radius, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)
  368. context.closePath()
  369. context.setBlendMode(.normal)
  370. context.drawPath(using: .stroke)
  371. case .diamond:
  372. var points = [CGPoint](repeating: .zero, count: 4)
  373. rpoint = diamondPoints(points: &points, point: endPoint, cpoint: startPoint)
  374. context.beginPath()
  375. context.addLines(between: points)
  376. context.closePath()
  377. context.setBlendMode(.normal)
  378. context.drawPath(using: .stroke)
  379. default:break
  380. }
  381. return rpoint
  382. }
  383. func openArrowPoints(points: UnsafeMutablePointer<CGPoint>, point: CGPoint, cpoint: CGPoint) -> CGPoint {
  384. let len: CGFloat = 4 + thickness
  385. var dx: CGFloat = 0, dy: CGFloat = 0
  386. var point0 = CGPoint.zero
  387. var point1 = CGPoint.zero
  388. var point2 = CGPoint.zero
  389. let mAB = (point.x - cpoint.x) * (point.x - cpoint.x) + (point.y - cpoint.y) * (point.y - cpoint.y)
  390. dx = (point.x - cpoint.x) * len / sqrt(mAB)
  391. dy = (point.y - cpoint.y) * len / sqrt(mAB)
  392. point0.x = point.x - dx
  393. point0.y = point.y - dy
  394. let mCB = (point.x - point0.x) * (point.x - point0.x) + (point.y - point0.y) * (point.y - point0.y)
  395. dx = -(point.y - point0.y) * len / sqrt(mCB)
  396. dy = (point.x - point0.x) * len / sqrt(mCB)
  397. point1.x = point0.x + dx
  398. point1.y = point0.y + dy
  399. point2.x = 2 * point0.x - point1.x
  400. point2.y = 2 * point0.y - point1.y
  401. // Assuming points is an array of CGPoint
  402. points[0] = point1
  403. points[1] = point
  404. points[2] = point2
  405. return point0
  406. }
  407. func closedArrowPoints(points: UnsafeMutablePointer<CGPoint>, point: CGPoint, cpoint: CGPoint) -> CGPoint {
  408. let len: CGFloat = 4
  409. var dx: CGFloat = 0, dy: CGFloat = 0
  410. var point0 = CGPoint.zero
  411. var point1 = CGPoint.zero
  412. var point2 = CGPoint.zero
  413. let mAB = (point.x - cpoint.x) * (point.x - cpoint.x) + (point.y - cpoint.y) * (point.y - cpoint.y)
  414. dx = (point.x - cpoint.x) * len / sqrt(mAB)
  415. dy = (point.y - cpoint.y) * len / sqrt(mAB)
  416. point0.x = point.x - dx
  417. point0.y = point.y - dy
  418. let mCB = (point.x - point0.x) * (point.x - point0.x) + (point.y - point0.y) * (point.y - point0.y)
  419. dx = -(point.y - point0.y) * len / sqrt(mCB)
  420. dy = (point.x - point0.x) * len / sqrt(mCB)
  421. point1.x = point0.x + dx
  422. point1.y = point0.y + dy
  423. point2.x = 2 * point0.x - point1.x
  424. point2.y = 2 * point0.y - point1.y
  425. // Assuming points is an array of CGPoint
  426. points[0] = point1
  427. points[1] = point
  428. points[2] = point2
  429. return point0
  430. }
  431. func squarePoints(points: UnsafeMutablePointer<CGPoint>, point: CGPoint, cpoint: CGPoint) -> CGPoint {
  432. let len = max(4, thickness)
  433. var dx: CGFloat = 0, dy: CGFloat = 0
  434. var point0 = CGPoint.zero
  435. var point1 = CGPoint.zero
  436. var point2 = CGPoint.zero
  437. var point3 = CGPoint.zero
  438. var point4 = CGPoint.zero
  439. var point5 = CGPoint.zero
  440. var point6 = CGPoint.zero
  441. let mAB = (point.x - cpoint.x) * (point.x - cpoint.x) + (point.y - cpoint.y) * (point.y - cpoint.y)
  442. dx = (point.x - cpoint.x) * len / sqrt(mAB)
  443. dy = (point.y - cpoint.y) * len / sqrt(mAB)
  444. point0.x = point.x - dx
  445. point0.y = point.y - dy
  446. point5.x = point.x - 2 * dx
  447. point5.y = point.y - 2 * dy
  448. point6.x = point.x + dx
  449. point6.y = point.y + dy
  450. let mCD = (point0.x - point5.x) * (point0.x - point5.x) + (point0.y - point5.y) * (point0.y - point5.y)
  451. dx = -(point0.y - point5.y) * len / sqrt(mCD)
  452. dy = (point0.x - point5.x) * len / sqrt(mCD)
  453. point1.x = point5.x + dx
  454. point1.y = point5.y + dy
  455. point2.x = 2 * point5.x - point1.x
  456. point2.y = 2 * point5.y - point1.y
  457. let mEB = (point6.x - point.x) * (point6.x - point.x) + (point6.y - point.y) * (point6.y - point.y)
  458. dx = -(point6.y - point.y) * len / sqrt(mEB)
  459. dy = (point6.x - point.x) * len / sqrt(mEB)
  460. point3.x = point.x + dx
  461. point3.y = point.y + dy
  462. point4.x = 2 * point.x - point3.x
  463. point4.y = 2 * point.y - point3.y
  464. points[0] = point1
  465. points[1] = point3
  466. points[2] = point4
  467. points[3] = point2
  468. return point5
  469. }
  470. func circlePoints(points: UnsafeMutablePointer<CGPoint>, point: CGPoint, cpoint: CGPoint) -> CGPoint {
  471. let len = max(4, thickness)
  472. var dx: CGFloat = 0, dy: CGFloat = 0
  473. var point0 = CGPoint.zero
  474. var point1 = CGPoint.zero
  475. let mAB = (point.x - cpoint.x) * (point.x - cpoint.x) + (point.y - cpoint.y) * (point.y - cpoint.y)
  476. dx = (point.x - cpoint.x) * len / sqrt(mAB)
  477. dy = (point.y - cpoint.y) * len / sqrt(mAB)
  478. point0.x = point.x - dx
  479. point0.y = point.y - dy
  480. point1.x = point.x - 2 * dx
  481. point1.y = point.y - 2 * dy
  482. points[0] = point0
  483. return point1
  484. }
  485. func diamondPoints(points: UnsafeMutablePointer<CGPoint>, point: CGPoint, cpoint: CGPoint) -> CGPoint {
  486. let len = max(4, thickness)
  487. var dx: CGFloat = 0, dy: CGFloat = 0
  488. var point0 = CGPoint.zero
  489. var point1 = CGPoint.zero
  490. var point2 = CGPoint.zero
  491. var point3 = CGPoint.zero
  492. let mAB = (point.x - cpoint.x) * (point.x - cpoint.x) + (point.y - cpoint.y) * (point.y - cpoint.y)
  493. dx = (point.x - cpoint.x) * len / sqrt(mAB)
  494. dy = (point.y - cpoint.y) * len / sqrt(mAB)
  495. point0.x = point.x - dx
  496. point0.y = point.y - dy
  497. point3.x = point.x - 2 * dx
  498. point3.y = point.y - 2 * dy
  499. let mCB = (point.x - point0.x) * (point.x - point0.x) + (point.y - point0.y) * (point.y - point0.y)
  500. dx = -(point.y - point0.y) * len / sqrt(mCB)
  501. dy = (point.x - point0.x) * len / sqrt(mCB)
  502. point1.x = point0.x + dx
  503. point1.y = point0.y + dy
  504. point2.x = 2 * point0.x - point1.x
  505. point2.y = 2 * point0.y - point1.y
  506. points[0] = point1
  507. points[1] = point
  508. points[2] = point2
  509. points[3] = point3
  510. return point3
  511. }
  512. }