//Add some comments to CircleView Sample Code.
//may help you understand the code or may be not.
</pre><pre name="code" class="objc">- (void)drawRect:(NSRect)rect {
NSUInteger glyphIndex;
NSRange glyphRange;
NSRect usedRect;
[[NSColor whiteColor] set];
NSRectFill([self bounds]);
// Note that usedRectForTextContainer: does not force layout, so it must
// be called after glyphRangeForTextContainer:, which does force layout.
glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
usedRect = [layoutManager usedRectForTextContainer:textContainer];
for (glyphIndex = glyphRange.location; glyphIndex < NSMaxRange(glyphRange); glyphIndex++) {
NSGraphicsContext *context = [NSGraphicsContext currentContext];
NSRect lineFragmentRect = [layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRange:NULL];
NSPoint viewLocation, layoutLocation = [layoutManager locationForGlyphAtIndex:glyphIndex];
CGFloat angle, distance;
NSAffineTransform *transform = [NSAffineTransform transform];
// Here layoutLocation is the location (in container coordinates) where the glyph was laid out.
layoutLocation.x += lineFragmentRect.origin.x;
layoutLocation.y += lineFragmentRect.origin.y;
// We then use the layoutLocation to calculate an appropriate position for the glyph
// around the circle (by angle and distance, or viewLocation in rectangular coordinates).
distance = radius + usedRect.size.height - layoutLocation.y; <span style="color:#33ff33;">//my: distance is a constant that a little larger than radius.</span>
angle = startingAngle + layoutLocation.x / distance;
<span style="color:#33ff33;">//my:
//This is a confusing point.
//In math, you calculate the coordinates of point of the circumference as:
//viewLocation.x = center.x + radium * cos(angle);
//viewLocation.y = center.y + radium * sin(angle);
//sin(PI/2 - alpha) = cos(alpha); cos(PI/2 - alpha) = sin(alpha);</span>
viewLocation.x = center.x + distance * sin(angle); <span style="color:#33ff33;">//sin(angle) = cos(PI/2 - angle) = cos(PI/2 - startingAngle - layoutLocation.x / distance);</span>
viewLocation.y = center.y + distance * cos(angle); <span style="color:#33ff33;">//cos(angle) = sin(PI/2 - angle) = sin(PI/2 - startingAngle - layoutLocation.x / distance);</span>
<span style="color:#33ff33;">//you can treat (PI/2 - startingAngle) as new startingAngle, the "-" before angle indicate
//as angle increase, points in circle move not counterclockwise but clockwise.</span>
// We use a different affine transform for each glyph, to position and rotate it
// based on its calculated position around the circle.
<span style="color:#33ff33;">// MY: If you don't known how the transformation works, you can refer to Cocoa Drawing Guide, search "Transform Basics".</span>
[transform translateXBy:viewLocation.x yBy:viewLocation.y];
[transform rotateByRadians:-angle];
<span style="color:#33ff33;">//-angle = -startingAngle - layoutLocation.x / distance = (PI/2 - startingAngle) + (- PI/2) - layoutLocation.x / distance.
//- layoutLocation.x / distance is alpha in my picture.</span>
// We save and restore the graphics state so that the transform applies only to this glyph.
[context saveGraphicsState];
[transform concat];
// drawGlyphsForGlyphRange: draws the glyph at its laid-out location in container coordinates.
// Since we are using the transform to place the glyph, we subtract the laid-out location here.
<span style="color:#33ff33;">//my:
//when invoke drawGlyphsForGlyphRange:atPoint, the origin point is the glyph's laid-out location in container coordinates.
//while x-direction and y-direction follows the transformed coordinate.
//so we subtract the laid-out location here.</span>
[layoutManager drawGlyphsForGlyphRange:NSMakeRange(glyphIndex, 1) atPoint:NSMakePoint(-layoutLocation.x, -layoutLocation.y)];
[context restoreGraphicsState];
}
}
//Comment: currently I can't upload my picture.