Skip to content

Commit 7997bcd

Browse files
authored
Merge pull request #7205 from ksen0/main
Refactor arc and rect to use canvas methods rather than curves
2 parents 4a2f704 + 967b676 commit 7997bcd

File tree

1 file changed

+32
-88
lines changed

1 file changed

+32
-88
lines changed

src/core/p5.Renderer2D.js

Lines changed: 32 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -532,42 +532,6 @@ class Renderer2D extends p5.Renderer {
532532
// SHAPE | 2D Primitives
533533
//////////////////////////////////////////////
534534

535-
/**
536-
* Generate a cubic Bezier representing an arc on the unit circle of total
537-
* angle `size` radians, beginning `start` radians above the x-axis. Up to
538-
* four of these curves are combined to make a full arc.
539-
*
540-
* See ecridge.com/bezier.pdf for an explanation of the method.
541-
*/
542-
_acuteArcToBezier(
543-
start,
544-
size
545-
) {
546-
// Evaluate constants.
547-
const alpha = size / 2.0,
548-
cos_alpha = Math.cos(alpha),
549-
sin_alpha = Math.sin(alpha),
550-
cot_alpha = 1.0 / Math.tan(alpha),
551-
// This is how far the arc needs to be rotated.
552-
phi = start + alpha,
553-
cos_phi = Math.cos(phi),
554-
sin_phi = Math.sin(phi),
555-
lambda = (4.0 - cos_alpha) / 3.0,
556-
mu = sin_alpha + (cos_alpha - lambda) * cot_alpha;
557-
558-
// Return rotated waypoints.
559-
return {
560-
ax: Math.cos(start).toFixed(7),
561-
ay: Math.sin(start).toFixed(7),
562-
bx: (lambda * cos_phi + mu * sin_phi).toFixed(7),
563-
by: (lambda * sin_phi - mu * cos_phi).toFixed(7),
564-
cx: (lambda * cos_phi - mu * sin_phi).toFixed(7),
565-
cy: (lambda * sin_phi + mu * cos_phi).toFixed(7),
566-
dx: Math.cos(start + size).toFixed(7),
567-
dy: Math.sin(start + size).toFixed(7)
568-
};
569-
}
570-
571535
/*
572536
* This function requires that:
573537
*
@@ -577,64 +541,51 @@ class Renderer2D extends p5.Renderer {
577541
*/
578542
arc(x, y, w, h, start, stop, mode) {
579543
const ctx = this.drawingContext;
580-
const rx = w / 2.0;
581-
const ry = h / 2.0;
582-
const epsilon = 0.00001; // Smallest visible angle on displays up to 4K.
583-
let arcToDraw = 0;
584-
const curves = [];
585-
586-
x += rx;
587-
y += ry;
588-
589-
// Create curves
590-
while (stop - start >= epsilon) {
591-
arcToDraw = Math.min(stop - start, constants.HALF_PI);
592-
curves.push(this._acuteArcToBezier(start, arcToDraw));
593-
start += arcToDraw;
594-
}
595544

596-
// Fill curves
545+
const centerX = x + w / 2,
546+
centerY = y + h / 2,
547+
radiusX = w / 2,
548+
radiusY = h / 2;
549+
550+
// Determines whether to add a line to the center, which should be done
551+
// when the mode is PIE or default; as well as when the start and end
552+
// angles do not form a full circle.
553+
const createPieSlice = ! (
554+
mode === constants.CHORD ||
555+
mode === constants.OPEN ||
556+
(stop - start) % constants.TWO_PI === 0
557+
);
558+
559+
// Fill
597560
if (this._doFill) {
598561
if (!this._clipping) ctx.beginPath();
599-
curves.forEach((curve, index) => {
600-
if (index === 0) {
601-
ctx.moveTo(x + curve.ax * rx, y + curve.ay * ry);
602-
}
603-
/* eslint-disable indent */
604-
ctx.bezierCurveTo(x + curve.bx * rx, y + curve.by * ry,
605-
x + curve.cx * rx, y + curve.cy * ry,
606-
x + curve.dx * rx, y + curve.dy * ry);
607-
/* eslint-enable indent */
608-
});
609-
if (mode === constants.PIE || mode == null) {
610-
ctx.lineTo(x, y);
611-
}
562+
ctx.ellipse(centerX, centerY, radiusX, radiusY, 0, start, stop);
563+
if (createPieSlice) ctx.lineTo(centerX, centerY);
612564
ctx.closePath();
613565
if (!this._clipping) ctx.fill();
614566
}
615567

616-
// Stroke curves
568+
// Stroke
617569
if (this._doStroke) {
618570
if (!this._clipping) ctx.beginPath();
619-
curves.forEach((curve, index) => {
620-
if (index === 0) {
621-
ctx.moveTo(x + curve.ax * rx, y + curve.ay * ry);
622-
}
623-
/* eslint-disable indent */
624-
ctx.bezierCurveTo(x + curve.bx * rx, y + curve.by * ry,
625-
x + curve.cx * rx, y + curve.cy * ry,
626-
x + curve.dx * rx, y + curve.dy * ry);
627-
/* eslint-enable indent */
628-
});
629-
if (mode === constants.PIE) {
630-
ctx.lineTo(x, y);
631-
ctx.closePath();
632-
} else if (mode === constants.CHORD) {
571+
ctx.ellipse(centerX, centerY, radiusX, radiusY, 0, start, stop);
572+
573+
if (mode === constants.PIE && createPieSlice) {
574+
// In PIE mode, stroke is added to the center and back to path,
575+
// unless the pie forms a complete ellipse (see: createPieSlice)
576+
ctx.lineTo(centerX, centerY);
577+
}
578+
579+
if (mode === constants.PIE || mode === constants.CHORD) {
580+
// Stroke connects back to path begin for both PIE and CHORD
633581
ctx.closePath();
634582
}
583+
635584
if (!this._clipping) ctx.stroke();
636585
}
586+
637587
return this;
588+
638589
}
639590

640591
ellipse(args) {
@@ -805,14 +756,7 @@ class Renderer2D extends p5.Renderer {
805756
bl = hh;
806757
}
807758

808-
// Draw shape
809-
if (!this._clipping) ctx.beginPath();
810-
ctx.moveTo(x + tl, y);
811-
ctx.arcTo(x + w, y, x + w, y + h, tr);
812-
ctx.arcTo(x + w, y + h, x, y + h, br);
813-
ctx.arcTo(x, y + h, x, y, bl);
814-
ctx.arcTo(x, y, x + w, y, tl);
815-
ctx.closePath();
759+
ctx.roundRect(x, y, w, h, [tl, tr, br, bl]);
816760
}
817761
if (!this._clipping && this._doFill) {
818762
ctx.fill();

0 commit comments

Comments
 (0)