Keeping a MKMapView within a region - objective-c

I'm trying to keep a specific region of the earth on screen at all times. I've looked around and found code that kinda works and sorta works but none that actually works... so I'm written up my own code and it's working better than what I've found except for one off behavior.
Dropping this method into a MKMapViewController will keep a region on the display and within a specific zoom range. If the region/zoom combination is smaller than the display, that is it is completely visible on the screen, then this works as expected.
If the region/zoom combination is larger than the screen things sorta work. I detect the out of bound and I move the map but it seems as if my offsets are flipped? I get in the cituation where the map "bounces" back and forth or up and down.
I can't seem to figure out what causes the bouncing or how to stop it.
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// Keep map in the zoom range we want
int zoom = self.map.zoomLevel;
if (self.map.zoomLevelFine > (float)self.maxZoom && self.maxZoom > 0)
{
zoom = self.maxZoom;
[self.map setCenterCoordinate:self.map.centerCoordinate zoomLevel:self.maxZoom animated:YES];
}
else if (self.map.zoomLevelFine < (float)self.minZoom && self.maxZoom > 0)
{
zoom = self.minZoom;
[self.map setCenterCoordinate:self.map.centerCoordinate zoomLevel:self.minZoom animated:YES];
}
// Figure out the current on screen boundry
MKCoordinateSpan span = self.map.region.span;
double north = self.map.centerCoordinate.latitude + (span.latitudeDelta / 2);
double south = self.map.centerCoordinate.latitude - (span.latitudeDelta / 2);
double east = self.map.centerCoordinate.longitude + (span.longitudeDelta / 2);
double west = self.map.centerCoordinate.longitude - (span.longitudeDelta / 2);
// get the offsets
float offsetLong = 0.0;
float offsetLat = 0.0;
if (self.topLeftLong < west && self.btmRightLong < east)
{
offsetLong = west - self.topLeftLong;
}
else if (self.topLeftLong > west && self.btmRightLong > east)
{
offsetLong = east - self.btmRightLong;
}
if (self.topLeftLat > north && self.btmRightLat > south)
{
offsetLat = north - self.topLeftLat;
}
else if (self.topLeftLat < north && self.btmRightLat < south)
{
offsetLat = south - self.btmRightLat;
}
// Keep the map on screen
if (offsetLat != 0.0 || offsetLong != 0.0)
{
[self.map setCenterCoordinate:CLLocationCoordinate2DMake(self.map.centerCoordinate.latitude - offsetLat,
self.map.centerCoordinate.longitude - offsetLong)
zoomLevel:zoom animated:YES];
}
// Debug
NSLog(#"Center: %f, %f, Zoom: %f", self.map.centerCoordinate.latitude, self.map.centerCoordinate.longitude, self.map.zoomLevelFine);
NSLog(#"A north: %f west: %f south: %f east: %f", north, west, south, east);
NSLog(#"B north: %f west: %f south: %f east: %f", self.topLeftLat, self.topLeftLong, self.btmRightLat, self.btmRightLong);
NSLog(#"offset %f, %f", offsetLong, offsetLat);
}
Adding this snippet into the init method will setup the map to show the island of Oahu on the screen.
// Get some basic setings
self.topLeftLat = 21.714852;
self.topLeftLong = -158.286896;
self.btmRightLat = 21.245862;
self.btmRightLong = -157.646942;
self.minZoom = 9.0;
self.maxZoom = 13.0;
The method above also uses a category to help manipulating the map.
MKMapView+Extra.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MKMapView (Extra)
#pragma mark -
#pragma mark Zoom methods
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel
animated:(BOOL)animated;
- (int) zoomLevel;
- (float) zoomLevelFine;
#pragma mark -
#pragma mark Region methods
- (void)setRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
animated:(BOOL)animated;
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight;
- (MKCoordinateSpan)spanFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight;
#end
MKMapView+Extra.m
#import "MKMapView+Extra.h"
#define MERCATOR_OFFSET 268435456
#define MERCATOR_RADIUS 85445659.44705395
#implementation MKMapView (ZoomLevel)
#pragma mark -
#pragma mark Map conversion methods
- (double)longitudeToPixelSpaceX:(double)longitude
{
return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
}
- (double)latitudeToPixelSpaceY:(double)latitude
{
return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
}
- (double)pixelSpaceXToLongitude:(double)pixelX
{
return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
}
- (double)pixelSpaceYToLatitude:(double)pixelY
{
return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
}
#pragma mark -
#pragma mark Helper methods
- (MKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
andZoomLevel:(NSUInteger)zoomLevel
{
// convert center coordiate to pixel space
double centerPixelX = [self longitudeToPixelSpaceX:centerCoordinate.longitude];
double centerPixelY = [self latitudeToPixelSpaceY:centerCoordinate.latitude];
// determine the scale value from the zoom level
NSInteger zoomExponent = 20 - zoomLevel;
double zoomScale = pow(2, zoomExponent);
// scale the map’s size in pixel space
CGSize mapSizeInPixels = mapView.bounds.size;
double scaledMapWidth = mapSizeInPixels.width * zoomScale;
double scaledMapHeight = mapSizeInPixels.height * zoomScale;
// figure out the position of the top-left pixel
double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
// find delta between left and right longitudes
CLLocationDegrees minLng = [self pixelSpaceXToLongitude:topLeftPixelX];
CLLocationDegrees maxLng = [self pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
CLLocationDegrees longitudeDelta = maxLng - minLng;
// find delta between top and bottom latitudes
CLLocationDegrees minLat = [self pixelSpaceYToLatitude:topLeftPixelY];
CLLocationDegrees maxLat = [self pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
// create and return the lat/lng span
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
return span;
}
#pragma mark -
#pragma mark Public zoom methods
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel
animated:(BOOL)animated
{
NSLog(#"setCenterCoordinate: zoomLevel:%d animated:", zoomLevel);
// clamp large numbers to 28
zoomLevel = MIN(zoomLevel-1, 28);
// use the zoom level to compute the region
MKCoordinateSpan span = [self coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
// set the region like normal
[self setRegion:region animated:animated];
}
- (int) zoomLevel
{
return 21 - round(log2(self.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * self.bounds.size.width)));
}
- (float) zoomLevelFine
{
return 21.0 - log2(self.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * self.bounds.size.width));
}
#pragma mark -
#pragma mark Public region methods
- (void)setRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
animated:(BOOL)animated
{
CLLocationCoordinate2D center = [self centerPointFromRegionTopLeft:topLeft bottomRight:bottomRight];
MKCoordinateSpan span = [self spanFromRegionTopLeft:topLeft bottomRight:bottomRight];
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
// set the region like normal
[self setRegion:region animated:animated];
}
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
{
CLLocationCoordinate2D centerPoint;
centerPoint.latitude = ((topLeft.latitude + bottomRight.latitude) / 2);
centerPoint.longitude = ((topLeft.longitude + bottomRight.longitude) / 2);
return centerPoint;
}
- (MKCoordinateSpan)spanFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
{
MKCoordinateSpan span;
span.latitudeDelta = fabs(bottomRight.latitude - topLeft.latitude);
span.longitudeDelta = fabs(bottomRight.longitude - topLeft.longitude);
return span;
}
#end

Related

How To Create a Rotating Wheel Control with UIKit

Hi I'm trying to create a Rotation Wheel in iOS and I found this fantastic tutorial
How to Create a Rotation Wheel Control
and it is very nice and complete, but in this case the selected object is in the left and need the object in the right.
So I'm wondering if somebody knows what I need to change in order to select the rigth side
Well in the example we can see in the endtrackingWithTouch Event the following code
// 1 - Get current container rotation in radians
CGFloat radians = atan2f(container.transform.b,container.transform.a);
NSLog(#"Radians %f", radians);
// 2 - Initialize new value
CGFloat newVal = 0.0;
// 3 - Iterate through all the sectors
for (SMSector *s in sectors) {
// 4 - Check for anomaly (occurs with even number of sectors)
if (s.minValue > 0 && s.maxValue < 0) {
if (s.maxValue > radians || s.minValue < radians) {
// 5 - Find the quadrant (positive or negative)
if (radians > 0) {
newVal = radians - M_PI;
} else {
newVal = M_PI + radians;
}
currentSector = s.sector;
}
}
// 6 - All non-anomalous cases
else if (radians > s.minValue && radians < s.maxValue) {
newVal = radians - s.midValue;
currentSector = s.sector;
}
}
Doing the Math for radians and making some comparing the min and max in the sectors we get the selected sector also if I change (CGFloat radians = atan2f(container.transform.b,container.transform.a);) for CGFloat radians = atan2f(container.transform.d,container.transform.c); I'm able to get the sector from the bottom
I think you can simply put your wheel in another view and rotate this view one PI. Something like this:
UIView *testView = [[UIView alloc]initWithFrame:CGRectMake(10, 80,300, 300)];
SMRotaryWheel *wheel = [[SMRotaryWheel alloc] initWithFrame:CGRectMake(0, 0,300, 300)
andDelegate:self
withSections:5];
[testView addSubview:wheel];
testView.transform = CGAffineTransformMakeRotation(M_PI);
[self.view addSubview:testView];

How to calculate positions and randoms in scene. SpriteKit

So here is a code :
static inline CGFloat randomInRange(CGFloat low, CGFloat high) {
CGFloat value = arc4random_uniform(UINT32_MAX) / (CGFloat)UINT32_MAX;
return value * (high - low) +low;
}
static const CGFloat HALO_LOW_ANGLE = 200.0 * M_PI / 180;
static const CGFloat HALO_HIGH_ANGLE = 340.0 * M_PI / 180;
static const CGFloat HALO_SPEED = 100.0;
-(void) spawnHalo {
SKSpriteNode *halo = [SKSpriteNode spriteNodeWithImageNamed:#"Halo"];
halo.position = CGPointMake(randomInRange(halo.size.width / 2, self.size.width - (halo.size.width / 2)), self.size.height + (halo.size.height / 2));
halo.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
CGVector direction = radiansToVector(randomInRange(HALO_LOW_ANGLE, HALO_HIGH_ANGLE));
halo.physicsBody.velocity = CGVectorMake(direction.dx * HALO_SPEED, direction.dy * HALO_SPEED);
halo.physicsBody.restitution = 1.0;
halo.physicsBody.linearDamping = 0.0;
halo.physicsBody.friction = 0.0;
[self.mainLayer addChild:halo];
I get that first we wanted to get a random value between 0-1. but what i really don't understand is how to calculate the coordinates.
What if i want to spawn the sprite from anywhere, make it the right,left or the bottom of the scene. How do i actually calculate that ?
This should do the trick:
CGPoint randomPosition = CGPointMake(arc4random() % (int)CGRectGetWidth(yourSceneInstance.frame),
arc4random() % (int)CGRectGetHeight(yourSceneInstance.frame));

Parametric Expression of a Bezier Curve

I have used the Parametric Expression of a Bezier Curve to locate a point along my curve and it's working as it should. The problem is I'm setting my t value as the percentage of the y axis and unfortunately (and obviously) it doesn't correlate because my curve is longer than my Y axis. So in this program if I set my Y Value to 75 I want to return the point on my line that sits at the Y value of 25 (the inverse because in iOS the (0, 0) sits at the top left instead of the bottom left as my graph reads). Currently setting my Y value retunes the point on my curve at 75% which has a Y of 15.62.
Anyone have a recommendation of how to get the point on my curve at Y instead of at 75%?
This is a follow-up question to a previous question, finding a point on a path, but I felt it was different enough to warrant its own thread.
#import "GraphView.h"
#interface GraphView ()
{
float yVal;
}
#end
#implementation GraphView
#synthesize myLabel, yValue;
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
yVal = 50;
}
return self;
}
- (IBAction)yValueTextField:(id)sender
{
yVal = yValue.text.intValue;
[self resignFirstResponder];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
float t = yVal / 100;
// Starting point
float p1x = 0;
float p1y = 100;
// Control point 1
float c1x = 50;
float c1y = 100;
// Control point 2
float c2x = 50;
float c2y = 0;
// End Point
float p2x = 100;
float p2y = 0;
CGPoint p1 = CGPointMake(p1x, p1y);
CGPoint c1 = CGPointMake(c1x, c1y);
CGPoint c2 = CGPointMake(c2x, c2y);
CGPoint p2 = CGPointMake(p2x, p2y);
// Cubic Bezier Curver Parmetic Expression
float X = pow((1 - t), 3) * p1x + 3 * pow((1 - t), 2) * t * c1x + 3 * (1 - t) * pow(t, 2) * c2x + pow(t, 3) * p2x;
float Y = pow((1 - t), 3) * p1y + 3 * pow((1 - t), 2) * t * c1y + 3 * (1 - t) * pow(t, 2) * c2y + pow(t, 3) * p2y;
myLabel.text = [NSString stringWithFormat:#"Coord = %.2f, %.2f", X, Y];
UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake((X - 2), (Y - 2), 4, 4)];
[[UIColor blackColor] setFill];
[circle fill];
UIBezierPath *curve = [[UIBezierPath alloc] init];
[curve moveToPoint:p1];
[curve addCurveToPoint:p2 controlPoint1:c1 controlPoint2:c2];
[curve setLineWidth:1];
[[UIColor blueColor] setStroke];
[curve stroke];
}
#end
Here is my solution to finding my point on my bezier curve. For more background regarding this see another related post of mine --> finding a point on a path
#import "Calculation.h"
#implementation Calculation
#synthesize a, b, c, d, xy;
- (float) calc
{
float squareRootCalc =
sqrt(
6*pow(xy,2)*b*d
+4*a*pow(c,3)
-3*pow(b,2)*pow(c,2)
+9*pow(xy,2)*pow(c,2)
-6*a*c*b*d
+6*a*xy*c*b
-18*pow(xy,2)*b*c
+6*a*pow(xy,2)*c
-12*a*xy*pow(c,2)
-2*pow(a,2)*xy*d
+pow(a,2)*pow(d,2)
+4*pow(b,3)*d
+pow(xy,2)*pow(d,2)
-4*pow(b,3)*xy
-4*pow(c,3)*xy
+pow(a,2)*pow(xy,2)
+6*c*b*d*xy
+6*a*c*d*xy
+6*a*b*d*xy
-12*pow(b,2)*d*xy
+6*xy*c*pow(b,2)
+6*xy*b*pow(c,2)
-2*a*pow(xy,2)*d
-2*a*xy*pow(d,2)
-6*c*d*pow(xy,2)
+9*pow(xy,2)*pow(b,2)
-6*a*pow(xy,2)*b)
;
float aCalc = 24*c*d*xy + 24*a*pow(c,2) - 36*xy*pow(c,2) + 4 * squareRootCalc * a;
float bCalc = -12 * squareRootCalc * b;
float cCalc = 12 * squareRootCalc * c;
float dCalc = -4 * squareRootCalc * d;
float xyCalc =
24*xy*a*b
-24*xy*b*d
-12*b*a*d
-12*c*a*d
-12*c*b*d
+8*xy*a*d
+8*pow(b,3)
+8*pow(c,3)
+4*pow(a,2)*d
+24*pow(b,2)*d
-4*xy*pow(a,2)
-4*xy*pow(d,2)
+4*a*pow(d,2)
-12*c*pow(b,2)
-12*b*pow(c,2)
-12*a*b*c
-24*xy*a*c
+72*xy*c*b
-36*xy*pow(b,2)
;
float cubeRootCalc = cbrt(aCalc + bCalc + cCalc + dCalc + xyCalc);
float denomCalc = (a-3*b+3*c-d);
float secOneCalc = 0.5 * cubeRootCalc / denomCalc;
float secTwoCalc = -2 * ((a*c - a*d - pow(b,2) + c*b + b*d - pow(c,2)) / (denomCalc * cubeRootCalc));
float secThreeCalc = (a - 2*b + c) / denomCalc;
return secOneCalc + secTwoCalc + secThreeCalc;
}
- (Calculation *) initWithA:(float)p0 andB:(float)p1 andC:(float)p2 andD:(float)p3 andXy:(float)xyValue
{
self = [super init];
if (self) {
[self setA:p0];
[self setB:p1];
[self setC:p2];
[self setD:p3];
[self setXy:xyValue];
}
return self;
}
- (void) setA:(float)p0 andB:(float)p1 andC:(float)p2 andD:(float)p3 andXy:(float)xyValue
{
[self setA:p0];
[self setB:p1];
[self setC:p2];
[self setD:p3];
[self setXy:xyValue];
}
#end

Pointers, Invalid Operands to Binary, and Noobs

[Edit: Rectangle definition added at bottom.]
[Edit2: XYPoint interface added at bottom.]
I'm working on a method that checks if two rectangles overlap. (Yeah, I'm in Kochan's Programming in Objective-C, doing the exercises, and I am painfully new at this.) When I compile this, the error message is: "Invalid operands to binary +". I get it on the first if statement and on the if-else that follows it.
I think I have an issue with pointers, but Kochan doesn't talk about this much.
And, if I take out these lines, the rest of the method works just fine. And the relevant variables are all floating type.
Help?
Also, any other thoughts on the method would be totally welcome. (Like, how do I make lines of code not go out so long. Like I said, painfully new at this.)
-(void) overlap: (Rectangle *)r2
{
overlapRectangle = [[Rectangle alloc] init];
leftRectangle = [[Rectangle alloc] init];
rightRectangle = [[Rectangle alloc] init];
lowerRectangle = [[Rectangle alloc] init];
upperRectangle = [[Rectangle alloc] init];
BOOL xIntersect = NO;
BOOL yIntersect = NO;
// Test to see if the Rectangle contains, or is equal to, Rectangle b
if (origin.x <= r2.origin.x && origin.y <= r2.origin.y && (origin.x + width) >= (r2.origin + r2.width) && (origin.y + height) >= (r2.origin.y + r2.height) )
{
overlapRectangle = r2;
}
// Test to see if Retangle b contains, or is equal to, the Rectangle
else if (origin.x >= r2.origin.x && origin.y >= r2.origin.y && origin.x + width <= r2.origin + r2.width && origin.y + height <= r2.origin.y + r2.height )
{
overlapRectangle = self;
}
// I should add tests for triangles overlapping on three
// sides or overlapping on two sides, but I'm not going
// to right now. Just learning objects and methods.
// Test to see if rectangles overlap on the x-axis
// Current is an if, because I wanted to run the code below
// to see if it worked, and it did.
if (origin.x <= r2.origin.x)
{
leftRectangle = self;
rightRectangle = r2;
}
else
{
rightRectangle = self;
leftRectangle = r2;
}
if (rightRectangle.origin.x + rightRectangle.width > leftRectangle.origin.x)
{
xIntersect = YES;
}
// Test to see if rectangles overlap on the y-axis
if (origin.y <= r2.origin.y)
{
lowerRectangle = self;
upperRectangle = r2;
}
else
{
lowerRectangle = self;
upperRectangle = r2;
}
if (lowerRectangle.origin.y + lowerRectangle.height > upperRectangle.origin.y)
{
yIntersect = YES;
}
// If retangles overlap on both the x-axis and y-axis,
// determination of overlapping rectangle's origin, height, and width
// and display same.
if (xIntersect == YES && yIntersect == YES)
{
overlapRectangle.origin.y = upperRectangle.origin.y;
overlapRectangle.origin.x = rightRectangle.origin.x;
overlapRectangle.height = lowerRectangle.height - (upperRectangle.origin.y - lowerRectangle.origin.y);
overlapRectangle.width = leftRectangle.width - (rightRectangle.origin.x - leftRectangle.origin.x);
NSLog (#"Your rectangles overlap.");
NSLog (#"Rectangle: w = %g, h = %g", overlapRectangle.width, overlapRectangle.height);
NSLog (#"Area = %g, Perimeter = %g", [overlapRectangle area], [overlapRectangle perimeter]);
NSLog (#"Origin at (%g, %g)", overlapRectangle.origin.x, overlapRectangle.origin.y);
}
else
{
NSLog (#"Your rectangles do not overlap.");
}
[overlapRectangle autorelease];
[leftRectangle autorelease];
[rightRectangle autorelease];
[lowerRectangle autorelease];
[upperRectangle autorelease];
}
Rectangle Definition:
// Interface, Rectangle Class
#interface Rectangle : NSObject
{
float width;
float height;
XYPoint *origin;
// For overlapping calculations
Rectangle *overlapRectangle;
Rectangle *leftRectangle;
Rectangle *rightRectangle;
Rectangle *lowerRectangle;
Rectangle *upperRectangle;
}
#property float width, height;
-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
-(void) setWidth: (float) w andHeight: (float) h;
-(float) area;
-(float) perimeter;
-(void) print;
-(void) translate;
-(void) overlap: (Rectangle *)r2;
-(void) draw;
#end
XYPoint interface:
#import <Foundation/Foundation.h>
#interface XYPoint : NSObject
{
float x;
float y;
}
#property float x, y;
-(void) setX: (float) xVal andY: (float) yVal;
#end
You've just got what is probably a typo:
// Test to see if the Rectangle contains, or is equal to,
// Rectangle b
if (origin.x <= r2.origin.x && origin.y <= r2.origin.y &&
(origin.x + width) >= (r2.origin + r2.width) &&
//^^^This is trying to add an XYPoint,
// which is an object, to a float.
(origin.y + height) >= (r2.origin.y + r2.height) )
{
overlapRectangle = r2;
}
// Test to see if Rectangle b contains, or is equal to,
// the Rectangle
else if (origin.x >= r2.origin.x && origin.y >= r2.origin.y &&
origin.x + width <= r2.origin + r2.width &&
//^^^Same thing.
origin.y + height <= r2.origin.y + r2.height )
{
...
The compiler should have told you what the types were that you were asking to be added:
error: invalid operands to binary + (have 'struct XYPoint *' and 'float')
that's the key. You just need to change the r2.origin to r2.origin.x so that you're adding two floats.
As for the length of the lines, there's two things you can do. You can move each segment of the conditions to different lines as I've done, but it would probably be best to create a couple of methods for Rectangle that will do the tests for you. This will make the code more readable, so when you come back to it in six months and the line reads:
if( [self containsRectangle:r2] || [self isEqualToRectangle:r2] ){
you'll know what's going on right away. Here's some suggestions for that:
- (BOOL)containsRectangle:(Rectangle *)otherRect {
BOOL originBelow = ((origin.x <= otherRect.origin.x) &&
(origin.y <= otherRect.origin.y));
float maxX = origin.x + width;
float otherMaxX = otherRect.origin.x + otherRect.width;
BOOL maxXGreater = maxX >= otherMaxX;
Bfloat maxY = origin.y + height;
float otherMaxY = otherRect.origin.y + otherRect.height;
BOOL maxYGreater = maxY >= otherMaxY;
return originBelow && maxXGreater && maxYGreater;
}
- (BOOL)isEqualToRectangle:(Rectangle *)otherRect {
BOOL sizeEqual = ((width == otherRect.width) &&
(height == otherRect.height));
return sizeEqual && [origin isEqualToXYPoint:otherRect.origin];
}
Note: I didn't test these, just pasted them together from the conditions of your ifs, so double-check them before you use them. I did fix the typo, though.
Notice that I also made up a method on XYPoint here, isEqualToXYPoint:; you can implement that as well, to return a BOOL if the x and y of both XYPoints are equal.

help to calculate atan2 properly

I need to calculate the angle between lines. I need to calculate atan. So I am using such code
static inline CGFloat angleBetweenLinesInRadians2(CGPoint line1Start, CGPoint line1End)
{
CGFloat dx = 0, dy = 0;
dx = line1End.x - line1Start.x;
dy = line1End.y - line1Start.y;
NSLog(#"\ndx = %f\ndy = %f", dx, dy);
CGFloat rads = fabs(atan2(dy, dx));
return rads;
}
But I can't get over 180 degrees(( After 179 deg going 178..160..150 and so on.
I need to rotate on 360 degrees. How can I do it? What's wrong?
maby this helps:
//Tells the receiver when one or more fingers associated with an event move within a view or window.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *Touches = [touches allObjects];
UITouch *first = [Touches objectAtIndex:0];
CGPoint b = [first previousLocationInView:[self imgView]]; //prewious position
CGPoint c = [first locationInView:[self imgView]]; //current position
CGFloat rad1 = angleBetweenLinesInRadians2(center, b); //first angel
CGFloat rad2 = angleBetweenLinesInRadians2(center, c); //second angel
CGFloat radAngle = fabs(rad2 - rad1); //angel between two lines
if (tempCount <= gradus)
{
[imgView setTransform: CGAffineTransformRotate([imgView transform], radAngle)];
tempCount += radAngle;
}
}
atan2 returns results in [-180,180] (or -pi, pi in radians). To get results from 0,360 use:
float radians = atan2(dy, dx);
if (radians < 0) {
radians += M_PI*2.0f;
}
It should be noted that it is typical to express rotations in [-pi,pi] and thusly you can just use the result of atan2 without worrying about the sign.
Remove the fabs call and simply make it:
CGFloat rads = atan2(dy, dx);
Use this function in Swift. This makes sure the angle from "fromPoint" to "toPoint" lands between 0 to <360 (not including 360). Please note, the following function assumes that CGPointZero is at top left corner.
func getAngle(fromPoint: CGPoint, toPoint: CGPoint) -> CGFloat {
let dx: CGFloat = fromPoint.x - toPoint.x
let dy: CGFloat = fromPoint.y - toPoint.y
let twoPi: CGFloat = 2 * CGFloat(M_PI)
let radians: CGFloat = (atan2(dy, -dx) + twoPi) % twoPi
return radians * 360 / twoPi
}
For the case where the origin is at the bottom left corner
let twoPi = 2 * Float(M_PI)
let radians = (atan2(-dy, -dx) + twoPi) % twoPi
let angle = radians * 360 / twoPi
Your problem is that the result of atan2 is between -180 and +180 degrees.
If you want it to be between 0 and 360 then move the result to sure be a positive value, and then do a modulo. For example:
let angle = fmod(atan2(dx,dy) + .pi * 2, .pi * 2)