问题
I created a view by drawing an arc of dots around the perimeter of a circle using iOS Core Graphics. Dot centres are calculated, stored in an array and retrieved using CGContextAddArc before being rendered to screen. I have every confidence in methods used to draw perimeter dots which may be [A] outlined, [B] filled with one colour, [C] alternately filled and outlined, and [D] filled with a sequence of five colours as shown.

However if centre dots are added to the array the properties of the last dots drawn on the perimeter change.
The simplest way to demonstrate this condition is to draw perimeter dots outlined with the addition of [E] the small centred dot [F] the large centred dot and [G] both centred dots; in each case, both small and large centred dots are expected to be filled green. With [H] there is also a problem when both centred dots are outlined not filled.

I have been learning Core Graphics for a month and need help to identify the edge condition that causes this. I would really welcome the insights of a more experienced core graphics programmer. Thanks.
Here is the implementation code; firstly, the method to initialise view settings.
- (void)ViewSettings_WaitView {
sectors = 80; // number of dots on perimeter
limit = sectors;
uberRadius = 52; // radius of large circle perimeter
dotRadius = 4; // radius of dots on large circle perimeter
dotsFilled = FALSE; // fill every with colour or outline
oneColour = FALSE; // every colour or one colour
alternateDots = FALSE; // alternately filled and outlined
ringDot = 64; // 64:show 0:hide
ringDotFilled = TRUE; // fill or outlined
centreDot = 26; // 26:show 0:hide
centreDotFilled = FALSE; // fill or outlined
[self centreReference]; // set up arc drawing to start from 12 o'clock position
[self selectZone]; // emulate 1-of-5 colours selected in GlobalView
}
And here is the code that draws these images
- (void)drawCircle {
context = UIGraphicsGetCurrentContext(); // Get the Graphics Context
CGContextSetLineWidth(context, 0.5); // Set the circle outerline-width
dotPosition = CGPointMake(uberX,uberY); // centre point for ring dot and centre dot
// create ring dot (larger centre dot)
if (ringDot != 0) {
iOSCircle *newCircle = [[iOSCircle alloc] init]; // Create a new iOSCircle Object
newCircle.circleRadius = ringDot; // ringDot radius
newCircle.circleCentre = dotPosition; // place ringDot on the frame
[totalCircles addObject:newCircle]; // add to the circle Array
[self setNeedsDisplay]; // update the view
NSLog(@"ringDot added:%@ radius: %f", NSStringFromCGPoint(dotPosition), ringDot);
}
// create centre dot (smaller centre dot)
if (centreDot != 0) {
iOSCircle *newCircle = [[iOSCircle alloc] init]; // Create a new iOSCircle Object
newCircle.circleRadius = centreDot; // ringDot radius
newCircle.circleCentre = dotPosition; // place ringDot on the frame
[totalCircles addObject:newCircle]; // add to the circle Array
[self setNeedsDisplay]; // update the view
NSLog(@"centreDot added:%@ radius: %f", NSStringFromCGPoint(dotPosition), centreDot);
}
// create sector dots (on perimeter of the arc)
for (dotCount = 1; dotCount < limit+1; dotCount++)
{
iOSCircle *newCircle = [[iOSCircle alloc] init]; // Create a new iOSCircle Object
newCircle.circleRadius = dotRadius;
[self newCentre]; // create a new x and y point for each sector dot
dotPosition = CGPointMake(x,y); // create each sector dot
newCircle.circleCentre = dotPosition; // place each dot on the frame
[totalCircles addObject:newCircle]; // add to the circle Array
[self setNeedsDisplay]; // update the view
NSLog(@"Dot %i %@", dotCount, NSStringFromCGPoint(dotPosition));
}
dotCount = 1;
for (iOSCircle *circle in totalCircles) { // Loop through array and retrieve dot dimensions
CGContextAddArc(context, circle.circleCentre.x, circle.circleCentre.y, circle.circleRadius, 0.0, M_PI * 2.0, YES);
[self renderSectorDots]; // render dots to view
dotCount++;
}
if (ringDot != 0) {
NSLog(@"add ringDot %@ radius: %f", NSStringFromCGPoint(dotPosition), ringDot);
[self renderRingDot];
}
if (centreDot != 0) {
NSLog(@"add centreDot %@ radius: %f", NSStringFromCGPoint(dotPosition), centreDot);
[self renderCentreDot];
}
}
And the methods for rendering centre dot (ring dot is similar)
- (void)renderCentreDot {
switch (centreDotFilled) {
case 1:
colourIndex = selectedZone;
[self whatColour];
break;
default:
[self dotOutline];
break;
}
}
- (void)whatColour {
switch (colourIndex) {
case 1:
// Fill the circle with cyan
[self paintCyan];
break;
case 2:
// Fill the circle with red
[self paintRed];
break;
case 3:
// Fill the circle with yellow
[self paintYellow];
break;
case 4:
// Fill the circle with magenta
[self paintMagenta];
break;
case 5:
// Fill the circle with green
[self paintGreen];
break;
default:
break;
}
}
- (void)dotOutline {
CGContextStrokePath(context); // draw outerline only
}
- (void)paintGreen {
CGContextSetFillColorWithColor(context, [[UIColor greenColor] CGColor]);
CGContextDrawPath(context, kCGPathFillStroke); // fill with outerline-colour
}
And finally the method for calculating new centres for the sector dots
- (void)newCentre {
dotAngle = dotAngle + uberAngle;
x = uberX + (uberRadius * 2 * cos(dotAngle));
y = uberY + (uberRadius * 2 * sin(dotAngle));
// NSLog(@"%i %f %f %f", dotCount, dotAngle, endAngle, uberAngle);
}
and a method to initialise centre parameters and start drawing from 12 o'clock position
- (void)centreReference {
uberX = 160;
uberY = 240;
uberAngle = (2.0 * PI) / sectors;
dotAngle = PI * -0.5; // start drawing 0.5 PI radians before 3 o'clock
endAngle = PI * 1.5; // stop drawing 1.5 PI radians after 3 o'clock
NSLog(@"%f %f %f %f", uberX, ringY, uberRadius, uberAngle);
}
回答1:
You have 80 outer circles and 0, 1, or 2 inner circles. All of these circles are stored in a single array called totalCircles
, and the inner circles are stored at the front of the array. So if you have two inner circles, totalCircles
has 82 elements.
The problem is that you're only drawing the first 80 circles: two inner circles and 78 outer circles.
Then you attempt to fill in one of the inner circles, but instead fill in the 79th outer circle.
In other words, you're losing track of which circles are which.
Try structuring your code in the following way:
You already have a "iOSCircle" object, which is good. This circle object should also contain its color and have the ability to draw itself:
@interface Circle : NSObject
@property (nonatomic) CGPoint centre;
@property (nonatomic) CGFloat radius;
@property (nonatomic, strong) UIColor* color;
- (void)draw;
@end
The -draw
method draws the circle, optionally filling the color
if it is set:
- (void)draw
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddArc(ctx, self.centre.x, self.centre.y, etc...)
if (self.color)
{
[self.color setFill];
CGContextDrawPath(ctx, kCGPathFillStroke);
}
else
{
CGContextStrokePath(ctx);
}
}
You should have a method that generates an array of circle objects. This will create the 80 outer circles, and optionally the inner circles. This will also assign a color to each circle.
Your main drawing method then as simple as this:
- (void)drawCircle
{
NSArray* circles = [self generateCircles];
for (Circle* circle in circles)
{
[circle draw];
}
}
来源:https://stackoverflow.com/questions/28378461/what-is-causing-this-edge-condition-with-cgcontextaddarc