在OSX中的NSView上使用Core Graphics绘制速度计

4

我正在尝试使用OSX上的核心图形(Core Graphics)绘制速度表的元素。我已经接近完成,但需要在表盘内部的中心刻度上获得一点帮助。这是我想要做的图片:

enter image description here

这是我目前的图像:

enter image description here

我知道如何绘制圆环,以及如何围绕仪表的中心绘制分段,就像这样:

- (void)drawOuterGaugeRingsInRect:(CGContextRef)contextRef rect:(NSRect)rect {


    CGContextSetLineWidth(contextRef,self.gaugeRingWidth);

    CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeOuterRingGray].CGColor);
    CGFloat startRadians = 0;
    CGFloat endRadians =  M_PI*2;
    CGFloat radius = self.bounds.size.width/2 - 5;

    CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startRadians,endRadians,YES);
    //Render the outer gauge
    CGContextStrokePath(contextRef);

    //Draw the inner gauge ring.
    radius -= self.gaugeRingWidth;
    CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeInnerRingGray].CGColor);
    CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startRadians,endRadians,YES);

    //Render the inner gauge
    CGContextStrokePath(contextRef);

    radius -= self.gaugeRingWidth;

    //Draw and fill the gauge background

    CGContextSetFillColorWithColor(contextRef, [MyColors SpeedGaugeCenterFillBlack ].CGColor);
    CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeCenterFillBlack].CGColor);
    CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startRadians,endRadians,YES);

    //Render and fill the gauge background
    CGContextDrawPath(contextRef, kCGPathFillStroke);


    /*BLUE CIRCULAR DIAL */
    //Prepare to draw the blue circular dial.
    radius -= self.gaugeRingWidth/2;

    //Adjust gauge ring width
    CGContextSetLineWidth(contextRef,self.gaugeRingWidth/2);

    CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeBlue].CGColor);

    CGFloat startingRadians = [MyMathHelper degressToRadians:135];
    CGFloat endingRadians = [MyMathHelper degressToRadians:45];


    CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startingRadians,endingRadians,NO);

    //Render the blue gauge line
    CGContextStrokePath(contextRef);
}

上述代码在我的NSViewdrawRect:方法中调用。

关键部分是这里的代码:

- (void)drawInnerDividerLines:(CGContextRef)context rect:(NSRect)rect {

    CGFloat centerX = CGRectGetMidX(rect);
    CGFloat centerY = CGRectGetMidY(rect);


    CGContextSetLineWidth       (context, 3.0);
    CGContextSetRGBStrokeColor  (context, 37.0/255.0, 204.0/255.0, 227.0/255.0, 0.5);



    CGFloat destinationX = centerX + (centerY * (cos((135)*(M_PI/180))));
    CGFloat destinationY = centerY + (centerX * (sin((135)*(M_PI/180))));

    NSPoint destinationPoint = NSMakePoint(destinationX, destinationY);


    CGContextMoveToPoint(context, centerX, centerY);

    CGContextAddLineToPoint(context, destinationPoint.x, destinationPoint.y);

    CGContextStrokePath(context);

}

我知道这里发生了什么,但我要解决的问题是如何绘制小线条,它们从内部蓝线延伸到视图的中心点,但并不一直绘制到中心。我有点不确定如何修改数学和绘图逻辑以实现这一点。这是我为核心图形绘制所基于的单位圆。

enter image description here

我试图解决的主要问题是:
  1. 如何定义适当的起点,作为每个标尺刻度的起始点,从内部浅蓝线开始。现在,我正在从中心画出整条线到仪表的边缘。

  2. 如何控制标尺刻度的长度,使其朝向中心,并从蓝线上的起点绘制。

如有任何提示或建议,可以帮助我解决这些问题,将不胜感激。
3个回答

2

我建议使用向量。通过计算,您可以找到任何角度上的圆上的点的线:

dirX = cos(angle);
dirY = sin(angle);
startPt.x = center.x + innerRadius * dirX;
startPt.y = center.y + innerRadius * dirY;
endPt.x = center.x + outerRadius * dirX;
endPt.y = center.y + outerRadius * dirY;

您可以在startPtendPt之间绘制一条线。

1
任何能指导我解决这个问题的提示或建议都将不胜感激。
给定圆周上某一点的角度,您可以形成一个直角三角形,半径是斜边,另外两条边平行于x和y轴(暂时忽略点在0、90、180或270度的退化情况)。使用正弦和余弦公式(从学校记得SOHCAHTOA)以及一些基本数学知识,您可以计算出该点的坐标,并使用它从中心绘制半径。
“刻度”标记的端点仅位于不同半径的圆上,因此相同的数学方法将给出端点,您可以绘制刻度。您只需要决定这些圆的半径,即应沿原始半径移动刻度的端点距离。
希望对您有所帮助。

0

避免三角函数的另一种方法是旋转变换矩阵,只需绘制垂直或水平线。

// A vertical "line" of width "width" along the y axis at x==0.
NSRect tick = NSMakeRect(-width / 2.0, innerRadius, width, outerRadius - innerRadius);
NSAffineTransform* xform = [NSAffineTransform transform];
// Move the x and y axes to the center of your speedometer so rotation happens around it
[xform translateXBy:center.x yBy:center.y];
// Rotate the coordinate system so that straight up is actually at your speedometer's 0
[xform rotateByDegrees:135];
[xform concat];
// Create a new transform to rotate back around for each tick.
xform = [NSAffineTransform transform];
[xform rotateByDegrees:-270.0 / numTicks];
for (int i = 0; i < numTicks; i++)
{
    NSRectFill(tick);
   [xform concat];
}

你可能想要将这个包装在[NSGraphicsContext saveGraphicsState][NSGraphicsContext restoreGraphicsState]中,这样当你完成时,变换矩阵就会被恢复。

如果你想要两种不同类型的刻度标记(主要和次要),那么可以有两个不同的矩形,并根据i % 10 == 0或其他条件选择其中一个。也许还可以切换颜色等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接