with the help i am able to draw circle with the coordinated using:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5.0);
CGContextSetStrokeColorWithColor(context,[UIColor grayColor].CGColor);
/**** Get values from reponse and fill it in this array. ******/
NSArray *objectCoords = [NSArray arrayWithObjects: #"{{20,80},{5,5}}", #"{{120,60},{5,5}}", #"{{60,84},{5,5}}", #"{{80,88},{5,5}}", #"{{100,93},{5,5}}", #"{{20,20},{5,5}}", #"{{160,70},{5,5}}", #"{{128,68},{5,5}}", #"{{90,60},{5,5}}", #"{{110,80},{5,5}}", nil];
for (NSString* objectCoord in objectCoords) {
CGRect coord = CGRectFromString(objectCoord);
// Draw using your coord
CGContextAddEllipseInRect(context, coord);
}
Now what i am trying to achieve is draw lines between the points(circle),as shown in the attached image.I know we can draw a line between 2 points, but here in this case, the lines needs to be drawn between one to multiple point/circle .Please suggest me to achieve this result.
You can just draw multiple lines. First, come up with a model to represent between which points you want to draw lines. For example, you could have an array of lines, where each line is defined, itself, as an array with the indices of two points, the starting point and the ending point.
For example, if you want to draw lines from point 1 to 3, 4, and 5, and from point 3 to 4 and 5, and between 4 and 5, you could do something like:
CGContextSetLineWidth(context, 1.0);
NSArray *lines = #[#[#(1), #(3)],
#[#(1), #(4)],
#[#(1), #(5)],
#[#(3), #(4)],
#[#(3), #(5)],
#[#(4), #(5)]];
for (NSArray *points in lines) {
NSInteger startIndex = [points[0] integerValue];
NSInteger endIndex = [points[1] integerValue];
CGRect startRect = CGRectFromString(objectCoords[startIndex]);
CGRect endRect = CGRectFromString(objectCoords[endIndex]);
CGContextMoveToPoint(context, CGRectGetMidX(startRect), CGRectGetMidY(startRect));
CGContextAddLineToPoint(context, CGRectGetMidX(endRect), CGRectGetMidY(endRect));
}
CGContextDrawPath(context, kCGPathStroke);
There are tons of different ways of doing it, but just come up with some model that represents where you want to draw the lines, and then iterate through that model to draw all of the individual lines.
If you wanted to have every point draw lines to the three closest points (which is not what your picture does, but it's what you asked for in a subsequent comment), you can:
build array of indices, indices in your objectCoords array; and
now iterate through each point in objectCoords:
build new array of indices, sortedIndices, sorted by the distance that the point represented by that index is from the current object in objectCoords; and
draw the three closest lines.
Thus:
// build array of indices (0, 1, 2, ...)
NSMutableArray *indices = [NSMutableArray array];
[objectCoords enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[indices addObject:#(idx)];
}];
// now go through all of the points in objectCoords
[objectCoords enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
// build new array of indices sorted by distance from the current point
NSArray *sortedIndices = [indices sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
CGFloat distance1 = [self distanceFromPointAtIndex:idx
toPointAtIndex:[obj1 integerValue]
usingObjectCoords:objectCoords];
CGFloat distance2 = [self distanceFromPointAtIndex:idx
toPointAtIndex:[obj2 integerValue]
usingObjectCoords:objectCoords];
if (distance1 < distance2)
return NSOrderedAscending;
else if (distance1 > distance2)
return NSOrderedDescending;
return NSOrderedSame;
}];
// now draw lines to the three closest indices
// (skipping 0, because that's probably the current point)
for (NSInteger i = 1; i < 4 && i < [sortedIndices count]; i++) {
NSInteger index = [sortedIndices[i] integerValue];
CGRect startRect = CGRectFromString(objectCoords[idx]);
CGRect endRect = CGRectFromString(objectCoords[index]);
CGContextMoveToPoint(context, CGRectGetMidX(startRect), CGRectGetMidY(startRect));
CGContextAddLineToPoint(context, CGRectGetMidX(endRect), CGRectGetMidY(endRect));
}
}];
CGContextSetLineWidth(context, 1);
CGContextDrawPath(context, kCGPathStroke);
And this uses the following method to calculate the distance between two points:
- (CGFloat)distanceFromPointAtIndex:(NSInteger)index1 toPointAtIndex:(NSInteger)index2 usingObjectCoords:(NSArray *)objectCoords
{
CGRect rect1 = CGRectFromString(objectCoords[index1]);
CGRect rect2 = CGRectFromString(objectCoords[index2]);
return hypotf(CGRectGetMidX(rect1) - CGRectGetMidX(rect2), CGRectGetMidY(rect1) - CGRectGetMidY(rect2));
}
Using the objectCoords in your original example, that yields:
This is a little unrelated to your original question, but rather than an array of strings, like so:
NSArray *objectCoords = #[#"{{20,80},{5,5}}",
#"{{120,60},{5,5}}",
#"{{60,84},{5,5}}",
#"{{80,88},{5,5}}",
#"{{100,93},{5,5}}",
#"{{20,20},{5,5}}",
#"{{160,70},{5,5}}",
#"{{128,68},{5,5}}",
#"{{90,60},{5,5}}",
#"{{110,80},{5,5}}"];
I might suggest employing an array of NSValue objects:
NSArray *objectCoords = #[[NSValue valueWithCGRect:CGRectMake(20,80,5,5)],
[NSValue valueWithCGRect:CGRectMake(120,60,5,5)],
[NSValue valueWithCGRect:CGRectMake(60,84,5,5)],
[NSValue valueWithCGRect:CGRectMake(80,88,5,5)],
[NSValue valueWithCGRect:CGRectMake(100,93,5,5)],
[NSValue valueWithCGRect:CGRectMake(20,20,5,5)],
[NSValue valueWithCGRect:CGRectMake(160,70,5,5)],
[NSValue valueWithCGRect:CGRectMake(128,68,5,5)],
[NSValue valueWithCGRect:CGRectMake(90,60,5,5)],
[NSValue valueWithCGRect:CGRectMake(110,80,5,5)]];
Then, when you're extracting the CGRect value, instead of:
CGRect rect = CGRectFromString(objectCoords[index]);
You would do:
CGRect rect = [objectCoords[index] CGRectValue];
I know this looks more cumbersome, but using NSValue is going to be more efficient (which is useful when doing a lot or repeated calculations of distances).
Even better, you might want to define your own model object that more intuitively defines a point that you want to chart, e.g.:
#interface ChartPoint : NSObject
#property (nonatomic) CGPoint center;
#property (nonatomic) CGFloat radius;
#end
and
#implementation ChartPoint
+ (instancetype) chartPointWithCenter:(CGPoint)center radius:(CGFloat)radius
{
ChartPoint *chartPoint = [[ChartPoint alloc] init];
chartPoint.center = center;
chartPoint.radius = radius;
return chartPoint;
}
- (CGFloat)distanceToPoint:(ChartPoint *)otherPoint
{
return hypotf(self.center.x - otherPoint.center.x, self.center.y - otherPoint.center.y);
}
#end
And then you can create an array of them like so:
NSArray *objectCoords = #[[ChartPoint chartPointWithCenter:CGPointMake(20,80) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(120,60) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(60,84) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(80,88) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(100,93) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(20,20) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(160,70) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(128,68) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(90,60) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(110,80) radius:5]];
But this
avoids inefficient CGRectFromString;
avoids needing to do those repeated CGRectGetMidX and CGRectGetMidY calls to determine the center of the CGRect; and, most importantly,
more accurately represents what your objects really are.
Obviously, when you want to draw your points, instead of doing:
NSString *string = objectCoords[idx];
CGRect *rect = CGRectFromString(string);
CGContextAddEllipseInRect(context, rect);
You'd do:
ChartPoint *point = objectCoords[idx];
CGContextAddArc(context, point.center.x, point.center.y, point.radius, 0, M_PI * 2.0, YES);
Ok I am trying to deal a deck of cards at certain positions, but I am stuck at a spot. I am only dealing one less than the max. I am trying to deal to every spot in the index of the nsarray.
- (CGPoint)animateDealingToPlayer:(Player *)player withDelay:(NSTimeInterval)delay
{
self.frame = CGRectMake(-100.0f, -100.0f, CardWidth, CardHeight);
self.transform = CGAffineTransformMakeRotation(M_PI);
NSArray *position = [NSArray arrayWithObjects:
[NSValue valueWithCGPoint:CGPointMake(0, 0)],
[NSValue valueWithCGPoint:CGPointMake(0, 0)],
[NSValue valueWithCGPoint:CGPointMake(0, 0)],
[NSValue valueWithCGPoint:CGPointMake(0, 0)],
[NSValue valueWithCGPoint:CGPointMake(10, 50)],
nil];
for(int i=0; i<5; i++) {
NSValue *value = [position objectAtIndex:i];
CGPoint point = [value CGPointValue];
NSLog(#"%#",NSStringFromCGPoint(point));
self.center = point;
}
}
I am dealing the card at 10,50 and not dealing the card at previous positions such as 0,0. This is probably easy to solve, but I can't seem to remember how to fix this. Please help me. Also, note that I am still somewhat new to objective c so you may have to dumb this down if you solve this lol.
The problem is that you are setting the cards position 5 times without doing any animation or giving the card object a chance to be redrawn in between changing it's position. iOS doesn't actually position the card until the run loop gets a chance to fire. There are a number of possible solutions, but you should probably look into adding an animation block inside your loop so that the movement is queued for the the display.
I have the code in which i want to develop the graph.The code is,
NSArray *coordinate = [[NSArray alloc] initWithObjects: #"42,213", #"75,173", #"108,153", #"141,133", #"174,113", #"207,73", #"240,33", nil];
CGContextSetRGBFillColor(ctx, 255, 0, 0, 1.0);
CGContextSetLineWidth(ctx, 8.0);
for(int intIndex = 0; intIndex < [coordinate count]; fltX1+=33, intIndex++)
{
CGContextMoveToPoint(ctx, fltX1+37, fltY2+18);
CGPoint point = [[coordinate objectAtIndex:intIndex] CGPointValue];
CGContextAddLineToPoint(ctx, point);
CGContextStrokePath(ctx);
}
I the above code goes in to debugger at the line of CGPoint point = [[coordinate objectAtIndex:intIndex] CGPointValue].
How i drawing the line in the graph using above code????????
Now i changing the above code as fllows,
Hi,glorifiedHacker,I already guessing above sentence.
But, now i changing the my code like,
CGContextSetRGBFillColor(ctx, 255, 0, 0, 1.0);
CGContextSetLineWidth(ctx, 8.0);
NSArray *coordinate1 = [[NSArray alloc] initWithObjects:#"42",#"75",#"108",#"141",#"174",#"207",#"240",nil];
NSLog(#"The points of coordinate1: %#", coordinate1);
NSArray *coordinate2 = [[NSArray alloc] initWithObjects:#"213",#"173",#"153",#"133",#"113",#"73",#"33",nil];
for(int intIndex = 0; intIndex < [coordinate1 count], intIndex < [coordinate2 count]; fltX1+=33, intIndex++)
{
CGContextMoveToPoint(ctx, fltX1+37, fltY2+18);
NSString *arrayDataForCoordinate1 = [coordinate1 objectAtIndex:intIndex];
NSString *arrayDataForCoordinate2 = [coordinate2 objectAtIndex:intIndex];
CGContextAddLineToPoint(ctx, (float *)arrayDataForCoordinate1, (float *)arrayDataForCoordinate2);
//NSLog(#"CGPoints of drawing the bar: %#", point);
}
CGContextClosePath(ctx);
CGContextStrokePath(ctx)
But it still given me error on same line.
Your graphics context likely doesn't have a path for you to add lines to at this point. Try wrapping your for loop in the appropriate "begin path" and "close path" function calls.
CGContextBeginPath(ctx);
for(int intIndex = 0; intIndex < [coordinate count]; fltX1 += 33, intIndex++) {
CGContextMoveToPoint(ctx, fltX1+37, fltY2+18);
CGPoint point = [[coordinate objectAtIndex:intIndex] CGPointValue];
CGContextAddLineToPoint(ctx, point.x, point.y);
}
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
Also, note that I moved the "stroke path" call outside of the for loop until you have closed the path.
Instead of typecasting an (NSString *) to a (float *) try [myString doubleValue]. If you have strings of the form "{x,y}" you can use CGPointFromString to convert directly to a point. If you can, avoid strings altogether and keep the original data as numeric types. If you must use an NSArray, that could be NSNumber pairs or NSValue of CGPoint.
I the above code goes in to debugger at the line of CGPoint point = [[coordinate objectAtIndex:intIndex] CGPointValue].
Because NSStrings don't respond to CGPointValue messages. You can see this for yourself by looking at the NSString documentation (or the Debugger Console, which will contain an exception message telling you this).
How i drawing the line in the graph using above code????????
Parse the strings yourself using NSScanner, or use the NSPointFromString function, or use a C array (not an NSArray) of NSPoints/CGPoints.
On an unrelated note:
for(int intIndex = 0; intIndex < [coordinate count]; fltX1+=33, intIndex++)
{
CGContextMoveToPoint(ctx, fltX1+37, fltY2+18);
Don't just drop random numeric literals into your code. You will have no idea what these numbers mean six months from now, and if you ever want to change, say, the horizontal offset of the graph, you will have to replace the number 37 everywhere in your app (except where it isn't the horizontal offset of the graph), not to mention any numbers that are 37 plus some other offset.
Instead, give these numbers names using something like this:
enum {
MyDistanceBetweenPoints = 33,
MyGraphOffsetX = 37,
MyGraphOffsetY = 18,
};
This way, if you want to change the horizontal offset of the graph, you don't need to hunt down every last relevant numeric literal; you need only change the definition of MyGraphOffsetX.
You can also use the current transformation matrix to offset the graph, thereby eliminating the additions from every CGContextMoveToPoint call and eliminating the risk that you'll forget an addition.