I\'m looking for an algorithm that allows me to create rounded corners from a polygon. In Input, I get an array of points that represents the polygon (red line) and in outpu
Objective-C adaptation of nempoBu4 answer:
typedef enum {
path_move_to,
path_line_to
} Path_command;
static inline CGFloat sqr (CGFloat a)
{
return a * a;
}
static inline CGFloat positive_angle (CGFloat angle)
{
return angle < 0 ? angle + 2 * (CGFloat) M_PI : angle;
}
static void add_corner (UIBezierPath* path, CGPoint p1, CGPoint p, CGPoint p2, CGFloat radius, Path_command first_add)
{
// 2
CGFloat angle = positive_angle (atan2f (p.y - p1.y, p.x - p1.x) - atan2f (p.y - p2.y, p.x - p2.x));
// 3
CGFloat segment = radius / fabsf (tanf (angle / 2));
CGFloat p_c1 = segment;
CGFloat p_c2 = segment;
// 4
CGFloat p_p1 = sqrtf (sqr (p.x - p1.x) + sqr (p.y - p1.y));
CGFloat p_p2 = sqrtf (sqr (p.x - p2.x) + sqr (p.y - p2.y));
CGFloat min = MIN(p_p1, p_p2);
if (segment > min) {
segment = min;
radius = segment * fabsf (tanf (angle / 2));
}
// 5
CGFloat p_o = sqrtf (sqr (radius) + sqr (segment));
// 6
CGPoint c1;
c1.x = (CGFloat) (p.x - (p.x - p1.x) * p_c1 / p_p1);
c1.y = (CGFloat) (p.y - (p.y - p1.y) * p_c1 / p_p1);
// 7
CGPoint c2;
c2.x = (CGFloat) (p.x - (p.x - p2.x) * p_c2 / p_p2);
c2.y = (CGFloat) (p.y - (p.y - p2.y) * p_c2 / p_p2);
// 8
CGFloat dx = p.x * 2 - c1.x - c2.x;
CGFloat dy = p.y * 2 - c1.y - c2.y;
CGFloat p_c = sqrtf (sqr (dx) + sqr (dy));
CGPoint o;
o.x = p.x - dx * p_o / p_c;
o.y = p.y - dy * p_o / p_c;
// 9
CGFloat start_angle = positive_angle (atan2f ((c1.y - o.y), (c1.x - o.x)));
CGFloat end_angle = positive_angle (atan2f ((c2.y - o.y), (c2.x - o.x)));
if (first_add == path_move_to) {
[path moveToPoint: c1];
}
else {
[path addLineToPoint: c1];
}
[path addArcWithCenter: o radius: radius startAngle: start_angle endAngle: end_angle clockwise: angle < M_PI];
}
UIBezierPath* path_with_rounded_corners (NSArray* points, CGFloat corner_radius)
{
UIBezierPath* path = [UIBezierPath bezierPath];
NSUInteger count = points.count;
for (NSUInteger i = 0; i < count; ++i) {
CGPoint prev = points[i > 0 ? i - 1 : count - 1].CGPointValue;
CGPoint p = points[i].CGPointValue;
CGPoint next = points[i + 1 < count ? i + 1 : 0].CGPointValue;
add_corner (path, prev, p, next, corner_radius, i == 0 ? path_move_to : path_line_to);
}
[path closePath];
return path;
}