I have a CGPoint declared in a UIView class, in my viewController I try to check if that CGPoint is not equal to CGPointZero, but I get this error:Invalid operands to binary expression ('CGPoint' (aka 'struct CGPoint') and 'CGPoint')
This is the if-statement:
if (joystick.velocity != CGPointZero)
The error points to the != and I dont know why it gives me an error.
joystick is the UIView class, CGPoint velocity is declared like this:
#property(nonatomic) CGPoint velocity;
Try this:
if (!CGPointEqualToPoint(joystick.velocity, CGPointZero))
Explanation: A CGPoint is actually a struct. The binary operand ("==" or "!=") it's only used to compare primitive values, usually useful to compare pointers, which in fact are integers representing a memory position.
As you have a struct, and not a reference to something, you would have to compare each value inside your struct, but fortunately apple already implemented a macro that performs this for you in the case of CGPoint.
If you are curious, you can command-click the macro above and see the implementation:
__CGPointEqualToPoint(CGPoint point1, CGPoint point2)
{
return point1.x == point2.x && point1.y == point2.y;
}
Related
According to this question, using == and != should let you check for equality between two CGPoint objects.
However, the code below fails to consider two CGPoint objects as equal even though they output the same value.
What is the right way to check equality among CGPoint objects?
Code:
let boardTilePos = boardLayer.convert(boardTile.position, from: boardTile.parent!)
let shapeTilePos = boardLayer.convert(tile.position, from: tile.parent!)
print("board tile pos: \(boardTilePos). active tile pos: \(shapeTilePos). true/false: \(shapeTilePos == boardTilePos)")
Output:
board tile pos: (175.0, 70.0). active tile pos: (175.0, 70.0). true/false: false
Unfortunately, what you see in the console is not what your real value is.
import UIKit
var x = CGPoint(x:175.0,y:70.0)
var y = CGPoint(x:175.0,y:70.00000000000001)
print("\(x.equalTo(y)), \(x == y),\(x),\(y)")
The problem is, the console only allows for 10-16 but in reality your CGFloat can go even lower than that because on 64bit architecture, CGFloat is Double.
This means you have to cast your CGPoint values to a Float if you want to get equality that will appear on the console, so you need to do something like:
if Float(boxA.x) == Float(boxB.x) && Float(boxA.y) == Float(boxB.y)
{
//We have equality
}
Now I like to take it one step further.
In most cases, we are using CGPoint to determine points on the scene. Rarely do we ever want to be dealing with 1/2 points, they make our lives just confusing.
So instead of Float, I like to cast to Int. This will guarantee if two points are lying on the same CGPoint in scene space
if Int(boxA.x) == Int(boxB.x) && Int(boxA.y) == Int(boxB.y)
{
//We have equality
}
I'm providing an alternate answer since I don't agree with Knight0fDragon's implementation. This is only if you want to deal with factions of a point. If you only care about points in whole numbers, see Knight0fDragon's answer.
You don't always have the luxury of logging points to the console, or seeing if you're trying to compare points that are the victim of floating point math, like comparing (175.0, 70.0) to (175.0, 70.00001) (which both log as (175.0, 70.0) in the console). Yes, truncating to Int is a great way of understanding why two points that appear to print to the console as equal aren't. But it's not a catch all solution one should use for comparing every point. Depending on what level of precision you need, you want to take the absolute value of the difference of both x and y for each point, and see if it is in an acceptable range of a delta you specify.
var boxA = CGPoint(x:175.0, y:70.0)
var boxB = CGPoint(x:175.0, y:70.00000000000001)
let delta: CGFloat = 0.01
if (fabs(boxA.x - boxB.x) < delta) &&
(fabs(boxA.y - boxB.y) < delta) {
// equal enough for our needs
}
The answer to the question "What is the right way to check equality among CGPoint objects?" really depends on the way you compare floating point numbers.
CGPoint provides its own comparison method: equalTo(_ point2: CGPoint)
Try this:
shapeTilePos.equalTo(boardTilePos)
I'm curious how I would use an if statement to see if a CGVector variable is nil, as objects are done like so:
if (!object){
//Do This
}
But with CGVector it's not an object (As I know of). How would I determine if my CGVector variable is nil?
As you know it is a struct not an object
struct CGVector {
CGFloat dx;
CGFloat dy;
};
typedef struct CGVector CGVector;
Edit:
There is no such thing to check if a struct is nil.
Even if you check with dx==0 and dy==0, this is not correct at all an {0,0} is still a valid vector point.
For similar approach/question : How do I check if a CGPoint has been initialised?
Im trying to figure out why this function do not execute theGameEnd function, when ball position is exactly the same as block position and when anchorpoints are the same.
if (CGPointEqualToPoint(ball.position,block.position)) {
if (CGPointEqualToPoint(ball.anchorPoint,monster1.anchorPoint)) {
[self theGameEnd];
}
}
The implementation of CGPointEqualToPoint is
CG_INLINE bool __CGPointEqualToPoint(CGPoint point1, CGPoint point2)
{
return point1.x == point2.x && point1.y == point2.y;
}
... so coordinates have to be absolutely equal to return true.
This is not always the case with CGFloat types, even if pixels seem to be aligned. There might be tiny errors resulting from the way you calculate them in your animation or game simulation code.
You could try to round the values before comparing them or allow for a small deviation.
I'm just curious why can't you access view.center.x or view.center.y but you can access view.center and change it.
I wanted to write this code:
imgView_.center = scrollView_.center;
if (imgView_.frame.origin.x < 0)
imgView_.center = CGPointMake(imgView_.center.x + (imgView_.frame.size.width - self.view.frame.size.width) / 2, imgView_.center.y);
if (imgView_.frame.origin.y < 0)
imgView_.center = CGPointMake(imgView_.center.x, imgView_.center.y + (imgView_.frame.size.height - self.view.frame.size.height) / 2);
As:
imgView_.center = scrollView_.center;
if (imgView_.frame.origin.x < 0)
imgView_.center.x = imgView_.center.x + (imgView_.frame.size.width - self.view.frame.size.width) / 2;
if (imgView_.frame.origin.y < 0)
imgView_.center.y = imgView_.center.y + (imgView_.frame.size.height - self.view.frame.size.height) / 2;
I find the second way a lot more elegant, but I can't access the x and y, so I thought I'd ask if anyone knows what's Apple's reason for blocking it.
See center property defined in UIView's UIViewGeometry category as below
#property(nonatomic) CGPoint center;
By declaration of center property, we have getter & setter methods for center property. it means we have setter & getter method for structure not for the values inside structure.
and Center is a CGPoint structure variable that has two CGFloat value x and y.
that's by we can't set directly x and y values in center property. it is similar to Frame property.
The UIView property center is a CGPoint which is of type struct and not an ObjectiveC class.
Even though writing this
view.center.x = view.center.x +10;
looks similar to
CGPoint center = view.center;
center.x = center.x +10;
view.center = center;
they are different things.
According to the compiler view.center is a method call [view center] and center.x is accessing the public ivar of the struct CGPoint. If you write all of this in a single line
view.center.x = view.center.x +10;
compiler is unable to resolve this and throws an error Expression is not assignable. Reason is view.center.x is further resolved as function call,
objc_msgSend(view, #selector(center))
Now you are trying to modify the return value of a C function as below
objc_msgSend(view, #selector(center)).x = 20 //(Some value on RHS)
which is not meaningful as the function return value isn't stored anywhere, hence the resulting expression is not assignable.
For more information read through this answer.
Hope that helps!
In the fragment imgView_.center.x the .center is a property access while the .x is a field access. The type of the property is CGPoint, which is a structure type which is passed by value.
If you have a variable of type CGPoint you can directly assign to individual fields, e.g.:
CGPoint myPoint;
myPoint.x = 3;
However when passing a CGPoint value to a function or method you cannot pass just one of it's fields - it makes no sense. E.g. if you have the function:
void doSomething(CGPoint aPoint);
you could pass myPoint:
doSomething(myPoint);
but there is no way to say "just pass the x field" - what would that even mean? The function is expecting a CGPoint, what would passing it one coordinate mean?
When you put the fragment imgView_.center on the left hand side of an assignment you are just using a shorthand for calling a method. E.g.:
imgView_.center = myPoint; <=> [imgView_ setCenter:myPoint];
and just like with the function above there is no way to say "just pass the x field".
The key point is a property access is not a variable access, even though it is often thought of as one, but a function/method call; so you can't assign to the individual fields of a property of structure type.
On the right hand side accessing a field of a property is fine. E.g. on the rhs imgView_.center translates to [imgView_ center] - which returns a CGPoint value, and you can access a field of structure value, so on the rhs imgView_.center.x translates to [imgView_ center].x and all is OK. But note that in both cases (setCenter: and center methods) the methods themselves take/return a complete CGPoint.
HTH.
i know how to make playin a sound but i don't know how to use the 'CGPointisEqualtoPoint' method. How do i use that or are there other ways?
-(void)beloning {
if (//CGPointisEqualtoPoint?!
) {
//play sound
}
From the docs:
Returns whether two points are equal.
bool CGPointEqualToPoint (
CGPoint point1,
CGPoint point2
);
But you may be better off with this one:
CGRectContainsPoint
Returns whether a rectangle contains a specified point.
bool CGRectContainsPoint (
CGRect rect,
CGPoint point
);
So now you can check if the rect of your image contains the coordinate point you care about