CLLocation becomes nan value for coordinate.latitude - objective-c

I have a view controller which is modally presented that displays a map view. So the map view works correctly with the following code, BUT there are 2 unused variables (long doubles x1, x2) and when I remove them the CLLocation always returns a nan value for the coordinate.latitude the third time the view controller is presented. temp1 value will be nan the third time and from then on.
WHY do I need these 2 unused variables?????, this is my question.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
navigationItemTitle.prompt = name;
if ([mapDict count] > 0)
{
id val = nil;
NSArray *values = [mapDict allValues];
long double x1, x2, temp1, temp2; //x1, x2 unused but necessary
for (int i = 0; i < [mapDict count]; i++)
{
val = [values objectAtIndex:i];
temp1 += ((CLLocation *)val).coordinate.latitude;
temp2 += ((CLLocation *)val).coordinate.longitude;
}
temp1 /= [values count];
temp2 /= [values count];
//NSLog(#"%Lf", temp1);
//NSLog(#"%Lf", temp2);
CLLocationCoordinate2D centerCooordinate = CLLocationCoordinate2DMake(temp1, temp2);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCooordinate, 10000000, 10000000);
[mapView setRegion:[mapView regionThatFits:region]];
for(id key in mapDict)
{
id value = [mapDict objectForKey:key];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = ((CLLocation *)value).coordinate;
point.title = key;
point.subtitle = [NSString stringWithFormat:#"%f\t%f", point.coordinate.latitude, point.coordinate.longitude];
[mapView addAnnotation:point];
}
}
}

The fact that the temp1 value is NaN only from the "third time" the view controller is presented is a coincidence.
Unlike instance variables, local variables are not initialized to any default values.
If you don't initialize them, they will have "random" values based on whatever is in their memory location at the time.
By declaring two "unused" variables, you're just changing the memory location of temp1 and temp2 which results in them taking slightly different default values.
To avoid this unpredictability, you should always initialize local variables.
Add these two lines before the for loop that calculates temp1 and temp2:
temp1 = 0.0;
temp2 = 0.0;
By the way, since iOS 7, you can avoid manually calculating the center coordinate by just calling showAnnotations after adding all the annotations.

Related

NSMutableArray array isn't created

On line that is marked with a comment "RIGHT HERE" (the last if statement) compiler tells me "index 0 beyond bounds for empty array" which I interpret as - the array wasn't created.
The idea is - in that last loop I'm going to sum up areas of already existing triangles with calc areas.
NSMutableArray *xCoordinate = [NSMutableArray array];
NSMutableArray *yCoordinate = [NSMutableArray array];
// some code in here...
int t;
int g = [xCoordinate count];
if (g<3) {
printf("Please enter at least 3 value pairs to form a polygon\n");
return 0;
}
NSMutableArray *arrayOfCorners = [NSMutableArray array];
NSMutableArray *arrayOfTriangls = [NSMutableArray array];
for (t=0; t < g; t++) {
float x = [[xCoordinate objectAtIndex:t] floatValue];
float y = [[yCoordinate objectAtIndex:t] floatValue];
RectangleCorner *corner = [[RectangleCorner alloc] initWithX:x andY:y];
// 3. add this corner to an array.
[arrayOfCorners addObject:corner];
if (t>=2) {
// 4. forming a triangle.
Triangle *triangle = [[Triangle alloc] init];
// 5. calc its sides length. Calculate lengths and assignes those values to side1, side2, side3 properties of the triangle.
[triangle sideLengthWithVert:arrayOfCorners[t] vert2:arrayOfCorners[t+1] vert3:arrayOfCorners[t+2]];
// 6. calc triangle area.
[triangle calcArea];
// 7. adding this triangle's area to our array
[arrayOfTriangls addObject:triangle];
}
// 8. adding up areas of triangles (if we have an array of them)
int i = 0;
NSInteger nsi = (NSInteger) i;
// RIGHT HERE.
Triangle *testingTriangle = [arrayOfTriangls objectAtIndex:nsi];
if (testingTriangle)
{
int y = [arrayOfTriangls count];
int r;
for (r=0; r<=y; r++) {
float p;
int q = r;
NSInteger ndi = (NSInteger) q;
Triangle *triangle = [arrayOfTriangls objectAtIndex:ndi];
p +=triangle.area;
printf("Polygon's Area is %f", p);
}
}
}
Lets walk through your code:
if (g<3) {
printf("Please enter at least 3 value pairs to form a polygon\n");
return 0;
}
NSMutableArray *arrayOfCorners = [NSMutableArray array];
NSMutableArray *arrayOfTriangls = [NSMutableArray array];
for (t=0; t < g; t++) {
You create array of triangles before the loop, then go with the for loop with at least g = 3.
Now lets start with t = 0, and go through the loop:
float x = [[xCoordinate objectAtIndex:t] floatValue];
float y = [[yCoordinate objectAtIndex:t] floatValue];
RectangleCorner *corner = [[RectangleCorner alloc] initWithX:x andY:y];
// 3. add this corner to an array.
[arrayOfCorners addObject:corner];
if (t>=2) {
// 4. forming a triangle.
Triangle *triangle = [[Triangle alloc] init];
// 5. calc its sides length. Calculate lengths and assignes those values to side1, side2, side3 properties of the triangle.
[triangle sideLengthWithVert:arrayOfCorners[t] vert2:arrayOfCorners[t+1] vert3:arrayOfCorners[t+2]];
// 6. calc triangle area.
[triangle calcArea];
// 7. adding this triangle's area to our array
[arrayOfTriangls addObject:triangle];
}
The if is not true at this point, so you didn't add a triangle yet to the array. The triangle array contains now 0 objects. Lets move on:
int i = 0;
NSInteger nsi = (NSInteger) i;
// RIGHT HERE.
Triangle *testingTriangle = [arrayOfTriangls objectAtIndex:nsi];
Now you try to get the object at index 0, but the array contains 0 objects. I suppose for t >= 2 your code works, but for t = 0, 1 your code crashes.
If your array was not created, arrayOfTriangls would be nil, and calling objectAtIndex: would return nil and not crash.
Instead, "index 0 beyond bounds for empty array" means that you tried to access the first element of an empty (but initialized) array.
Your problem is that your code 7. is not executed for the first two loop iteration (if t>=2), hence the empty array.

Plotting hits within given areas of circle - Code for setup getting bloated

[Alternative approach given by user1118321, old and new code listed for reference]
I am busy writing a small app which allows a game of darts 501 to be scored. I have set up a class to contain the individual scoring areas (GDSBoardArea) and one mutable array which represents the entire dart board and holds all the individual scoring class instances.
I have written the code for one section (20 score, inner and outer, and triple and double 20) but the issue I have is that the code for this is quite bloated and was woindering if there was a better way to init all the areas with less, more managable code as I will have to repeat this below another 19 times for the other sections?
I have a class that holds the settings for the various individual areas, one class to hold all these areas and helper functions.
I did attempt to try reuse the CGPoints and area arrays but this simply caused issues I think related to the fact that it updates a reference as the scoringAreas addObject does not copy the array object (Please correct me if I am wrong).
I setup the scoring areas once when the application runs using the createAreas function and I cant seem to reuse the CGPoints and arrays holding them.
My questions are:
1 - Is there a way to pass in a variable array of CGPoints to "GDSBoardArea"'s last parameter instead of having to create the CGPoints, add them to an array and pass the array in.
2 - Does the mutable array method addobject copy or reference the object passed to it? Is it there any way to update an array and then make a copy of it to a "master" mutable array so that the master array is effectively holding a different array in each element. I am basically try to avoid having to create a new array for each of the master arrays elements.
createAreas
-(void)createAreas
{
scoringAreas = [[NSMutableArray alloc] init];
/*
20 scoring section
*/
// 20 score - Inner triangle area
/////////////////////////////////////////
// Set up CGPoints for area
CGPoint pt_inner20_1 = CGPointMake(368.0f, 234.0f);
CGPoint pt_inner20_2 = CGPointMake(413.0f, 234.0f);
CGPoint pt_inner20_3 = CGPointMake(389.0f, 360.0f);
// Add points to array for passing to GDSBoardArea Class
NSMutableArray * areaPointsArray_Inner20 = [NSMutableArray array];
[areaPointsArray_Inner20 addObject:[NSValue valueWithCGPoint:pt_inner20_1]];
[areaPointsArray_Inner20 addObject:[NSValue valueWithCGPoint:pt_inner20_2]];
[areaPointsArray_Inner20 addObject:[NSValue valueWithCGPoint:pt_inner20_3]];
// Create GDSBoardArea Instance with init values
GDSBoardArea *scoreAreaFor_Inner20 = [[GDSBoardArea alloc] initWithName:#"20-Inner" abbrev:#"20" areaValue:20 pointsArray:NULL];
// Add Array of CGPoints to GDSScoreArea
[scoreAreaFor_Inner20 setPointsForPath:areaPointsArray_Inner20];
// Add ScoreArea to ScoreAreas Class
[scoringAreas addObject:scoreAreaFor_Inner20];
// 20 score - Outer Quadrilateral
/////////////////////////////////////////
CGPoint pt_outer20_1 = CGPointMake(353.0f, 125.0f);
CGPoint pt_outer20_2 = CGPointMake(429.0f, 127.0f);
CGPoint pt_outer20_3 = CGPointMake(415.0f, 208.0f);
CGPoint pt_outer20_4 = CGPointMake(365.0f, 209.0f);
NSMutableArray * areaPointsArray_Outer20 = [NSMutableArray array];
[areaPointsArray_Outer20 addObject:[NSValue valueWithCGPoint:pt_outer20_1]];
[areaPointsArray_Outer20 addObject:[NSValue valueWithCGPoint:pt_outer20_2]];
[areaPointsArray_Outer20 addObject:[NSValue valueWithCGPoint:pt_outer20_3]];
[areaPointsArray_Outer20 addObject:[NSValue valueWithCGPoint:pt_outer20_4]];
GDSBoardArea *scoreAreaFor_Outer20 = [[GDSBoardArea alloc] initWithName:#"20-Outer" abbrev:#"20" areaValue:20 pointsArray:NULL];
[scoreAreaFor_Outer20 setPointsForPath:areaPointsArray_Outer20];
[scoringAreas addObject:scoreAreaFor_Outer20];
// Double 20 Quadrilateral
/////////////////////////////////////////
CGPoint pt_d20_1 = CGPointMake(351.0f, 102.0f);
CGPoint pt_d20_2 = CGPointMake(353.0f, 118.0f);
CGPoint pt_d20_3 = CGPointMake(430.0f, 119.0f);
CGPoint pt_d20_4 = CGPointMake(433.0f, 104.0f);
NSMutableArray * areaPointsArray_Double20 = [NSMutableArray array];
[areaPointsArray_Double20 addObject:[NSValue valueWithCGPoint:pt_d20_1]];
[areaPointsArray_Double20 addObject:[NSValue valueWithCGPoint:pt_d20_2]];
[areaPointsArray_Double20 addObject:[NSValue valueWithCGPoint:pt_d20_3]];
[areaPointsArray_Double20 addObject:[NSValue valueWithCGPoint:pt_d20_4]];
GDSBoardArea *scoreAreaFor_double20 = [[GDSBoardArea alloc] initWithName:#"20-Double" abbrev:#"d20" areaValue:40 pointsArray:NULL];
[scoreAreaFor_double20 setPointsForPath:areaPointsArray_Double20];
[scoringAreas addObject:scoreAreaFor_double20];
// Triple 20 Quadrilateral
/////////////////////////////////////////
CGPoint pt_t20_1 = CGPointMake(367.0f, 214.0f);
CGPoint pt_t20_2 = CGPointMake(368.0f, 226.0f);
CGPoint pt_t20_3 = CGPointMake(412.0f, 226.0f);
CGPoint pt_t20_4 = CGPointMake(413.0f, 214.0f);
NSMutableArray * areaPointsArray_Triple20 = [NSMutableArray array];
[areaPointsArray_Triple20 addObject:[NSValue valueWithCGPoint:pt_t20_1]];
[areaPointsArray_Triple20 addObject:[NSValue valueWithCGPoint:pt_t20_2]];
[areaPointsArray_Triple20 addObject:[NSValue valueWithCGPoint:pt_t20_3]];
[areaPointsArray_Triple20 addObject:[NSValue valueWithCGPoint:pt_t20_4]];
GDSBoardArea *scoreAreaFor_triple20 = [[GDSBoardArea alloc] initWithName:#"20-Triple" abbrev:#"t20" areaValue:60 pointsArray:NULL];
[scoreAreaFor_triple20 setPointsForPath:areaPointsArray_Triple20];
[scoringAreas addObject:scoreAreaFor_triple20];
}
ScoringAreas is a Mutable Array that simplt represents all the areas of the board and is defined as:
#property (strong, atomic) NSMutableArray *scoringAreas;
GDSBoardArea Class in case its relevant
// GDSBoardArea.h
#import <Foundation/Foundation.h>
#interface GDSBoardArea : NSObject
#property NSMutableArray *pointsForPath;
#property int areaValue;
#property NSString *name;
#property NSString *abbrev;
-(id) init;
-(id)initWithName:(NSString *)name_ abbrev:(NSString *)abbrev_ areaValue:(int)areaValue_ pointsArray:(NSMutableArray*)pointsArray;
#end
--
// GDSBoardArea.m
#import "GDSBoardArea.h"
#implementation GDSBoardArea
-(id)init{
if (self = [super init]) {
/* perform your post-initialization logic here */
[self setName:#""];
[self setAbbrev:#""];
[self setAreaValue:0];
[self setPointsForPath:NULL];
}
return self;
}
-(id)initWithName:(NSString *)name_ abbrev:(NSString *)abbrev_ areaValue:(int)areaValue_ pointsArray:(NSMutableArray*)pointsArray
{
self = [super init];
if (self) {
self.name = name_;
self.abbrev = abbrev_;
self.areaValue = areaValue_;
self.pointsForPath = pointsArray;
}
return self;
}
#end
Code change as per answer from user1118321:
createAreas function was completely removed and direct calculation done as follows (Will add more as it is fleshed out until complete)
-(GDSBoardArea *)checkPointsScore:(CGPoint)tappedPoint
{
#define NUM_PIE_SLICES 20
#define NUM_RINGS 7
#define DEG_PER_SLICE 18
#define PII 3.141592653
#define OFFSETFORBOARD 99.3f
float radius_board = 344.0f;
float thickness_innerbull = 16.0f;
float thickness_outerbull = 18.0f;
float thickness_innerSingleScore = 116.0f;
float thickness_double = 16.0f;
float thickness_outerSingleScore = 80.0f;
float thickness_triple = 20.0f;
float thickness_noscore = 78.0f;
GDSBoardArea *tappedScoreArea = NULL;
double dartX = tappedPoint.x;
double dartY = tappedPoint.y;
double centerX = 390.0f;
double centerY = 390.0f;
double angle = atan2((dartY - centerY), (dartX - centerX)) * 180 / PII;
angle = angle + OFFSETFORBOARD; // To force slice 0 to correspond to Score of 20
int slice = (int)floor(angle / DEG_PER_SLICE);
NSLog(#"angle: %f", angle);
NSLog(#"slice #: %i", slice);
return tappedScoreArea;
}
If it were me, I wouldn't bother at all with storing the various areas of the board. First, they aren't triangles and quads, and second, it's fairly easy to calculate them. You can figure out which "pie slice" you're in by getting the arctangent of the point where the dart lands, like this:
double angle = atan2((dartY - centerY) / (dartX - centerX));
You can then convert that to an integer between 1 and # of slices like this:
int slice = (int)floor(angle / anglePerSlice);
Next, you can figure out which ring the user is in by using the distance from the board's center:
double deltaX = dartX - centerX;
double deltaY = dartY - centerY;
double distFromCenter = sqrt (deltaX * deltaX + deltaY * deltaY);
You could then convert that into an index by looking it up in an array. You have a single array containing all the boundaries in a single slice. All slices have their boundaries at the same distances. So it would look something like this:
double concentricBounds[kNumBounds] = { 10, 15, 100, 110, 200, 210 }; // Just made up - I don't know what distances you're using.
bool done = false;
int index = 0;
for (int i = 0; (i < kNumBounds) && (!done); i++)
{
if (distFromCenter < concentricBounds [ i ])
{
done = true;
index = i;
}
}
if (!done)
{
...point was off the board...
}
So now you have the slice it was in and the ring it's in. You can just have a 2D array of point values to look up into:
int points [][] = { {50, 25, 20, 60, 20, 40 }, { 50, 25, 5, 15, 5, 15 }, ...etc... };
Note that atan2() returns angles with 0° being parallel to the X-axis and it increases in counter-clockwise order. So you may have to rotate the scores to orient your board correctly.

Core Plot: Custom labels on the x-axis for bar charts

I am using Core Plot bar charts to plot company growth rates. I would like to have the company's stock symbols as the labels on the x-axis centered below their respective bars. Unfortunately I have spent many hours in searching for a way to center the x-labels correctly, but had no success using my code. How can I get the x-axis labels centered correctly?
My chart set-up is as follows:
CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor blueColor] horizontalBars:NO];
barPlot.baseValue = CPTDecimalFromInt(0);
barPlot.barOffset = CPTDecimalFromFloat(0.5f);
barPlot.barWidth = CPTDecimalFromFloat(0.5f);
double xAxisStart = 0;
double xAxisLength = self.companies.count;
double yAxisStart = 0;
double yAxisLength = 0.5;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(xAxisStart) length:CPTDecimalFromDouble(xAxisLength + 1.0)] ;
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(yAxisStart) length:CPTDecimalFromDouble(yAxisLength)] ;
barPlot.plotRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(+0.0) length:CPTDecimalFromDouble(xAxisLength)] ;
In the following code snippet, I tried to use custom labels, but without success as the sample chart below shows.
xAxis.labelingPolicy = CPTAxisLabelingPolicyNone;
NSMutableArray *customLabels = [[NSMutableArray alloc]init];
[self.companies enumerateObjectsUsingBlock:^(IBCompany *company, NSUInteger idx, BOOL *stop) {
NSString *labelText = company.contrSymbol;
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:labelText textStyle:xAxis.labelTextStyle];
label.tickLocation = CPTDecimalFromDouble(idx + 0.5);
label.offset = xAxis.labelOffset + xAxis.majorTickLength;
label.rotation = M_PI * 2;
[customLabels addObject:label];
}];
xAxis.axisLabels = [NSSet setWithArray:customLabels];
Please note that my index for the bar charts starts with 1:
-(NSArray *)numbersForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange
{
if ( [plot.identifier isEqual:plotIdentifier] ) {;
if ( fieldEnum == CPTScatterPlotFieldX ) {
NSMutableArray *indexArray = [[NSMutableArray alloc] init];
[self.companies enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[indexArray addObject:[NSDecimalNumber numberWithInt: idx + 1]];
}];
return [indexArray copy];
}
else if ( fieldEnum == CPTScatterPlotFieldY ) {
// ..
}
}
else return nil; // should be considered as ERROR
}
You should get in the habit of using the field identifiers for the right plot type in your datasource. For bar plots, you should be using CPTBarPlotFieldBarLocation and CPTBarPlotFieldBarTip. In this case there's no difference, but that's not always true with other plot types. For instance, the x and y coordinates are reversed for horizontal bar charts.
The datasource always returns the same dataset. You need to check the indexRange parameter and only return the range requested.
The plot range for the x-axis runs between 0 and 4. The labels are at 0.5, 1.5, and 2.5. The plotRange is what's messing up the bar spacing. Leave it set to the default of nil and you should get the appearance you want. From the plotRange docs:
If a plot range is provided, the bars are spaced evenly throughout the plot range. If plotRange is nil, bar locations are provided by Cocoa bindings or the bar plot datasource. If locations are not provided by either bindings or the datasource, the first bar will be placed at zero (0) and subsequent bars will be at successive positive integer coordinates.

Draw polyline between given points on the map

I am implementing an iOS application, and I want to draw a polyline between several given coordinates on the map.
I wrote the code and got the polylines being drawn from my point reaching an infinite point. In other words the beginning point of the line starts from the my given lat and long point, but the end of the line is infinite and not the other point.
This is my code...
I filled the coordinates in a NSMutableArray called routeLatitudes. The array cells are being filled one for latitude and one for longitude.
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * [routeLatitudes count]);
for(int idx = 0; idx < [routeLatitudes count]; idx=idx+2)
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude=[[routeLatitudes objectAtIndex:idx] doubleValue];
workingCoordinate.longitude=[[routeLatitudes objectAtIndex:idx+1] doubleValue];
MKMapPoint point = MKMapPointForCoordinate(workingCoordinate);
pointArr[idx] = point;
}
// create the polyline based on the array of points.
routeLine = [MKPolyline polylineWithPoints:pointArr count:[routeLatitudes count]];
[mapView addOverlay:self.routeLine];
free(pointArr);
and overlay delegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayView* overlayView = nil;
if(overlay == routeLine)
{
self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];
self.routeLineView.fillColor = [UIColor colorWithRed:51 green:51 blue:255 alpha:1];
self.routeLineView.strokeColor = [UIColor colorWithRed:204 green:0 blue:0 alpha:1];
self.routeLineView.lineWidth = 3;
overlayView = routeLineView;
}
return overlayView;
}
So I need the lines to be drawn between the points over the map. The beginning of the line is the first dropped pin, and the end is on the last dropped pin.
According to the code, the routeLatitudes array has objects listed like this:
index 0: latitude for point 1
index 1: longitude for point 1
index 2: latitude for point 2
index 3: longitude for point 2
index 4: latitude for point 3
index 5: longitude for point 3
...
So if routeLatitudes.count is 6, it actually has only 3 points.
This means the malloc is allocating the wrong number of points and the polylineWithPoints call is also specifying the wrong number of points for the overlay.
The other problem is that since pointArr will contain only half the objects that routeLatitudes has, you can't use the same index value for both arrays.
The for loop index counter idx is being incremented by 2 at each iteration because that's how the routeLatitudes points are layed out but then the same idx value is used to set pointArr.
So for idx=0, pointArr[0] is set but then for idx=2, pointArr[2] is set (instead of pointArr[1]), and so on. This means every other position in pointArr is left uninitialized resulting in the lines "going to infinity".
So the corrected code might look like this:
int pointCount = [routeLatitudes count] / 2;
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * pointCount);
int pointArrIndex = 0; //it's simpler to keep a separate index for pointArr
for (int idx = 0; idx < [routeLatitudes count]; idx=idx+2)
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude=[[routeLatitudes objectAtIndex:idx] doubleValue];
workingCoordinate.longitude=[[routeLatitudes objectAtIndex:idx+1] doubleValue];
MKMapPoint point = MKMapPointForCoordinate(workingCoordinate);
pointArr[pointArrIndex] = point;
pointArrIndex++;
}
// create the polyline based on the array of points.
routeLine = [MKPolyline polylineWithPoints:pointArr count:pointCount];
[mapView addOverlay:routeLine];
free(pointArr);
Also note in the malloc line, I corrected sizeof(CLLocationCoordinate2D) to sizeof(MKMapPoint). This technically wasn't causing a problem because those two structs happen to be the same length but it's correct to use sizeof(MKMapPoint) since that's what the array is going to contain.

Objective-C: Get closest NSView to dragged NSView

If I have a NSView with 10 subviews, and I drag one of the subviews, what is the easiest way to determine which of the remaining views is closes to the dragged one? My code is working but I somehow feel I'm using a monkey wrench to fine tune a violin. Is there a more elegant way?
subviews is an array of the subviews of the parent view of this view (so it includes this view)
the toolTip of the sub views contain their page # formatted like "Page_#"
- (void) mouseUp: (NSEvent* ) e {
//set up a ridiclous # for current distance
float mtDistance = 12000000.0;
//get this page number
selfPageNum = [[[self toolTip] substringFromIndex:5] intValue];
//set up pageViews array
pageViews = [[NSMutableArray alloc] init];
//loop through the subviews
for (int i=0; i<[subviews count]; i++) {
//set up the view
thisView = [subviews objectAtIndex:i];
//filter for view classes
NSString* thisViewClass = [NSString stringWithFormat:#"%#", [thisView className]];
if ( [thisViewClass isEqual:#"Page"]) {
//add to the pageViews array
[pageViews addObject:thisView];
if (self != thisView) {
//get the view and self frame
NSRect movedViewFrame = [self frame];
NSRect thisViewFrame = [thisView frame];
//get the location area (x*y)
float movedViewLoc = movedViewFrame.origin.x * (movedViewFrame.origin.y * -1);
float thisViewLoc = thisViewFrame.origin.x * (thisViewFrame.origin.y * -1);
//get the difference between x locations
float mtDifference = movedViewLoc - thisViewLoc;
if (mtDifference < 0) {
mtDifference = mtDifference * -1;
}
if (mtDifference < mtDistance) {
mtDistance = mtDifference;
closesView = thisView;
}
}
}//end class check
}//end loop
//....more stuff
}
http://en.wikipedia.org/wiki/Distance
sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2)))
Edit: Since you only need to find the shortest distance, not exact distances, you don't need to take the square root. Thanks for the insight Abizern
pow((x2 - x1), 2) + pow((y2 - y1), 2)