📜 ⬆️ ⬇️

A practical example of using operator overloading for CoreGraphics

Prehistory


Impressed by the articles about Sprite Kit and about GestureRecognizer , the idea arose of porting a simple application to your phone. And since CGPoint structures are often used there , I was puzzled by studying operator overloading in Swift and spied on it.

Implementation


In a few steps I created for myself some “library” of overload operators for convenient work with expressions for CGPoint structures. At the same time at each step, I tested the testing in XCode .

In fact, a complete algebra of operations is implemented for the linear space of vectors ( CGPoint structures), scalars ( CGFloat ) and partially operators ( CGAffineTransform ).

Since these functions of operator overload are described globally, the functionality is added to any project easily - by adding the source code.
')
Of course, there are quite a few examples of using overload on fictional situations, but this “library of operators” may turn out to be:

  1. a slightly more specific example
  2. A ready-made solution that saves a couple of hours of routine dialing and debugging the simplest code (the listing of the entire source is given at the end).

Step by step


Step 1: Vector Addition / Subtraction Operators
It should be noted, as in the second case, with the help of prefix , the unaryness of the prefix operator is indicated.

func +(left: CGPoint, right: CGPoint)->CGPoint{ return CGPoint(x: left.x+right.x, y: left.y+right.y) } prefix func -(right: CGPoint)->CGPoint{ return CGPoint(x: -right.x, y: -right.y) } func -(left: CGPoint, right: CGPoint)->CGPoint{ return left + (-right) } 


Step 2: multiply and divide the vector by a scalar
Here it is worth paying attention to the fact that the first two operators form the “symmetry” of multiplication of the scalar and vector.

 func *(left: CGPoint, right: CGFloat)->CGPoint{ return CGPoint(x: left.x*right, y: left.y*right) } func *(left: CGFloat, right: CGPoint)->CGPoint{ return right*left } func /(left: CGPoint, right: CGFloat)->CGPoint{ return left*(1/right) } 


Step 3: Combining the above operations with assignment
It is important to note how inout describes the mutability of the left argument, which is necessary for assignment operations.

 func +=(inout left:CGPoint, right:CGPoint){ left = left+right } func -=(inout left:CGPoint, right:CGPoint){ left = left-right } func *=(inout left:CGPoint, right:CGFloat){ left = left*right } func /=(inout left:CGPoint, right:CGFloat){ left = left/right } 


Step 4: scalar and 'mixed' product
Very useful things, since the first product gives a scalar and is proportional to the cosine of the angle between the vectors, and the second product is a pseudo-scalar (that is, changes sign when the factors are rearranged) and proportional to the sine of the angle between the vectors (the “rotation” gesture calculates the angle value most likely by base of this expression).

 func *(left: CGPoint, right: CGPoint)->CGFloat{ return left.x*right.x + left.y*right.y } func ^(left: CGPoint, right: CGPoint)->CGFloat{ return left.x*right.y - left.y*right.x } 


Step 5: Product of vector by affine transformation operator
Here, for the sake of order, only the multiplication of the vector by the operator on the right is introduced.

 func *(left: CGPoint, right: CGAffineTransform)->CGPoint{ return CGPointApplyAffineTransform(left, right) } func *=(inout left:CGPoint, right:CGAffineTransform){ left = left*right } 


Step 6: the product of affine transformation operators
 func *(left: CGAffineTransform, right: CGAffineTransform)->CGAffineTransform{ return CGAffineTransformConcat(left, right) } func *=(inout left:CGAffineTransform, right:CGAffineTransform){ left = left*right } 


Conclusion


The given example is a necessary and sufficient set in the current understanding of my needs. In particular, therefore, the algebra for matrices and for similar structures (eg, CGSize ) is not implemented.

I would also like to note that these solutions are so obvious and convenient that it would not be surprising if over time such an overload enters as part of the standard CoreGraphics library.

All code in its entirety
This can already be copied directly into the project.

 import Foundation func +(left: CGPoint, right: CGPoint)->CGPoint{ return CGPoint(x: left.x+right.x, y: left.y+right.y) } prefix func -(right: CGPoint)->CGPoint{ return CGPoint(x: -right.x, y: -right.y) } func -(left: CGPoint, right: CGPoint)->CGPoint{ return left + (-right) } /////////////////////////////////////////////////// func *(left: CGPoint, right: CGFloat)->CGPoint{ return CGPoint(x: left.x*right, y: left.y*right) } func *(left: CGFloat, right: CGPoint)->CGPoint{ return right*left } func /(left: CGPoint, right: CGFloat)->CGPoint{ return left*(1/right) } /////////////////////////////////////////////////// func +=(inout left:CGPoint, right:CGPoint){ left = left+right } func -=(inout left:CGPoint, right:CGPoint){ left = left-right } func *=(inout left:CGPoint, right:CGFloat){ left = left*right } func /=(inout left:CGPoint, right:CGFloat){ left = left/right } /////////////////////////////////////////////////// /////////////////////////////////////////////////// func *(left: CGPoint, right: CGPoint)->CGFloat{ return left.x*right.x + left.y*right.y } func /(left: CGPoint, right: CGPoint)->CGFloat{ return left.x*right.y - left.y*right.x } /////////////////////////////////////////////////// /////////////////////////////////////////////////// func *(left: CGPoint, right: CGAffineTransform)->CGPoint{ return CGPointApplyAffineTransform(left, right) } func *=(inout left:CGPoint, right:CGAffineTransform){ left = left*right } /////////////////////////////////////////////////// func *(left: CGAffineTransform, right: CGAffineTransform)->CGAffineTransform{ return CGAffineTransformConcat(left, right) } func *=(inout left:CGAffineTransform, right:CGAffineTransform){ left = left*right } 

Source: https://habr.com/ru/post/271647/


All Articles