function start() {
var rotation = Playground.AddFloat('rotation', 53);
var majorCenter = Playground.AddVector2('majorCenter', new Vector2(180, 200));
var majorRadius = Playground.AddFloat('majorRadius', 100);
var majorArc = Playground.AddFloat('majorArc', 290);
var minorRadius = Playground.AddFloat('minorRadius', 75);
var minorArc = Playground.AddFloat('minorArc', 275);
Playground.AddOptionFloat(rotation, 'Rotation', 1, 0, 360);
Playground.AddOptionVector2(majorCenter, 'Major center');
Playground.AddOptionFloat(majorRadius, 'Major radius', 0, 40, 150);
Playground.AddOptionFloat(majorArc, 'Major arc', 1, 0, 360);
Playground.AddOptionFloat(minorRadius, 'Minor radius', 0, 40, 150);
Playground.AddOptionFloat(minorArc, 'Minor arc', 1, 0, 360);
}
function update() {
var rotation = Playground.GetValueFloat('rotation');
var majorCenter = Playground.GetValueVector2('majorCenter');
var majorRadius = Playground.GetValueFloat('majorRadius');
var majorArc = Playground.GetValueFloat('majorArc');
var minorRadius = Playground.GetValueFloat('minorRadius');
var minorArc = Playground.GetValueFloat('minorArc');
var majorPoints = createCircle(majorRadius, majorArc, 1);
var minorPoints = createCircle(minorRadius, minorArc, -1);
var majorArcDelta = (majorArc % 90) / 90;
if (majorArc < 360) {
var splitMajorArc = splitBezier(
majorPoints[majorPoints.length - 4],
majorPoints[majorPoints.length - 3],
majorPoints[majorPoints.length - 2],
majorPoints[majorPoints.length - 1],
majorArcDelta);
majorPoints[majorPoints.length - 4] = splitMajorArc[0];
majorPoints[majorPoints.length - 3] = splitMajorArc[1];
majorPoints[majorPoints.length - 2] = splitMajorArc[2];
majorPoints[majorPoints.length - 1] = splitMajorArc[3];
}
var minorArcDelta = (minorArc % 90) / 90;
if (minorArc < 360) {
var splitMinorArc = splitBezier(
minorPoints[minorPoints.length - 4],
minorPoints[minorPoints.length - 3],
minorPoints[minorPoints.length - 2],
minorPoints[minorPoints.length - 1],
minorArcDelta);
minorPoints[minorPoints.length - 4] = splitMinorArc[0];
minorPoints[minorPoints.length - 3] = splitMinorArc[1];
minorPoints[minorPoints.length - 2] = splitMinorArc[2];
minorPoints[minorPoints.length - 1] = splitMinorArc[3];
}
majorPoints = majorPoints.map(function (p) {
return rotate(
add(p, majorCenter),
majorCenter,
rotation * Math.PI / 180);
});
var majorEnd = majorPoints[majorPoints.length - 1];
var minorCenter = add(majorEnd, scale(normalize(subtract(majorEnd, majorCenter)), minorRadius));
minorPoints = minorPoints.map(function (p) {
return rotate(
add(p, minorCenter),
minorCenter,
(majorArc + rotation) * Math.PI / 180 + Math.PI);
});
// Floating-point rounding error causes the major arc and minor arc to diverge, leading to an improper join.
// This is rectified manually.
var difference = subtract(majorPoints[majorPoints.length - 1], minorPoints[0]);
minorPoints = minorPoints.map(function (p) {
return add(p, difference);
});
Playground.AddSlider(CurveType.Bezier, majorPoints.concat(minorPoints));
}
function createCircle(radius, arc, y) {
var points = []
// Optimal cubic bézier anchor points for an approximation of a circular quadrant.
var c = radius * 4 / 3 * (Math.sqrt(2) - 1);
if (arc >= 90 * 0) {
points.push(new Vector2(radius, 0));
points.push(new Vector2(radius, y * c));
points.push(new Vector2(c, y * radius));
points.push(new Vector2(0, y * radius));
}
if (arc >= 90 * 1) {
points.push(new Vector2(0, y * radius));
points.push(new Vector2(-c, y * radius));
points.push(new Vector2(-radius, y * c));
points.push(new Vector2(-radius, 0));
}
if (arc >= 90 * 2) {
points.push(new Vector2(-radius, 0));
points.push(new Vector2(-radius, y * -c));
points.push(new Vector2(-c, y * -radius));
points.push(new Vector2(0, y * -radius));
}
if (arc >= 90 * 3) {
points.push(new Vector2(0, y * -radius));
points.push(new Vector2(c, y * -radius));
points.push(new Vector2(radius, y * -c));
points.push(new Vector2(radius, 0));
}
return points;
}
function splitBezier(p1, p2, p3, p4, t) {
var p12 = add(scale(subtract(p2, p1), t), p1);
var p23 = add(scale(subtract(p3, p2), t), p2);
var p34 = add(scale(subtract(p4, p3), t), p3);
var p123 = add(scale(subtract(p23, p12), t), p12);
var p234 = add(scale(subtract(p34, p23), t), p23);
var p1234 = add(scale(subtract(p234, p123), t), p123);
return [
p1,
p12,
p123,
p1234
];
}