For a recent project, I needed to have the ability for a user to draw an angle dimension on top of a picture. They can drag the 3 points and the dimension lines should update in real time. I needed to draw two lines and an arc between the two lines. Drawing the two lines is simple, but drawing the arc took a little bit of thinking.
At first I was calculating the inscribed angle using the law of cosines, then trying to determine the starting angle. The end angle would be the starting angle + the inscribed angle. Big mistake. This is complicated and has too many edge cases for each quadrant a starting or ending point is located in. Then I tried the handy atan2 function, which previously proved very useful in game design, and worked perfectly. In this case, imagine a line of 3 points, where each point can be moved and the angle between the two segments are shown.
Below is my drawing code to achieve this:
- (void)drawRect:(CGRect)rect { [super drawRect:rect]; CGFloat lx = self.leftEndpoint.center.x;// first point along edge CGFloat ly = self.leftEndpoint.center.y; CGFloat mx = self.middleEndpoint.center.x;// middle pt CGFloat my = self.middleEndpoint.center.y; CGFloat rx = self.rightEndpoint.center.x;// other point along edge CGFloat ry = self.rightEndpoint.center.y; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetStrokeColorWithColor(context, [self.lineColor CGColor]); // thickness CGContextSetLineWidth(context, 2.0f); // starting pt CGContextMoveToPoint(context, lx, ly); // middle pt CGContextAddLineToPoint(context, mx, my); // ending pt CGContextAddLineToPoint(context, rx, ry); // draw path, make sure to call this here to reset the stoke path points CGContextStrokePath(context); // angle arc // distances CGFloat lmDist = sqrt(pow(lx - mx, 2) + pow(ly - my, 2)); CGFloat mrDist = sqrt(pow(rx - mx, 2) + pow(ry - my, 2)); // angles CGFloat startAngle = atan2(ry - my, rx - mx);// right to middle CGFloat endAngle = atan2(ly - my, lx - mx);// left to middle CGFloat radius = 0.20 * fmin(lmDist, mrDist);// 20% of min distance along lines int clockwise = YES; CGContextAddArc(context, self.middleEndpoint.center.x, self.middleEndpoint.center.y, radius, startAngle, endAngle, clockwise); // draw arc path CGContextStrokePath(context); }
Here’s a screenshot from the prototype app:
(Ignore the background, it’s just something nice to look at while working)