| 8 | import canvas from '../core/helpers'; |
| 9 | |
| 10 | function primitives(p5, fn){ |
| 11 | /** |
| 12 | * This function does 3 things: |
| 13 | * |
| 14 | * 1. Bounds the desired start/stop angles for an arc (in radians) so that: |
| 15 | * |
| 16 | * 0 <= start < TWO_PI ; start <= stop < start + TWO_PI |
| 17 | * |
| 18 | * This means that the arc rendering functions don't have to be concerned |
| 19 | * with what happens if stop is smaller than start, or if the arc 'goes |
| 20 | * round more than once', etc.: they can just start at start and increase |
| 21 | * until stop and the correct arc will be drawn. |
| 22 | * |
| 23 | * 2. Optionally adjusts the angles within each quadrant to counter the naive |
| 24 | * scaling of the underlying ellipse up from the unit circle. Without |
| 25 | * this, the angles become arbitrary when width != height: 45 degrees |
| 26 | * might be drawn at 5 degrees on a 'wide' ellipse, or at 85 degrees on |
| 27 | * a 'tall' ellipse. |
| 28 | * |
| 29 | * 3. Flags up when start and stop correspond to the same place on the |
| 30 | * underlying ellipse. This is useful if you want to do something special |
| 31 | * there (like rendering a whole ellipse instead). |
| 32 | */ |
| 33 | fn._normalizeArcAngles = ( |
| 34 | start, |
| 35 | stop, |
| 36 | width, |
| 37 | height, |
| 38 | correctForScaling |
| 39 | ) => { |
| 40 | const epsilon = 0.00001; // Smallest visible angle on displays up to 4K. |
| 41 | let separation; |
| 42 | |
| 43 | // The order of the steps is important here: each one builds upon the |
| 44 | // adjustments made in the steps that precede it. |
| 45 | |
| 46 | // Constrain both start and stop to [0,TWO_PI). |
| 47 | start = start - constants.TWO_PI * Math.floor(start / constants.TWO_PI); |
| 48 | stop = stop - constants.TWO_PI * Math.floor(stop / constants.TWO_PI); |
| 49 | |
| 50 | // Get the angular separation between the requested start and stop points. |
| 51 | // |
| 52 | // Technically this separation only matches what gets drawn if |
| 53 | // correctForScaling is enabled. We could add a more complicated calculation |
| 54 | // for when the scaling is uncorrected (in which case the drawn points could |
| 55 | // end up pushed together or pulled apart quite dramatically relative to what |
| 56 | // was requested), but it would make things more opaque for little practical |
| 57 | // benefit. |
| 58 | // |
| 59 | // (If you do disable correctForScaling and find that correspondToSamePoint |
| 60 | // is set too aggressively, the easiest thing to do is probably to just make |
| 61 | // epsilon smaller...) |
| 62 | separation = Math.min( |
| 63 | Math.abs(start - stop), |
| 64 | constants.TWO_PI - Math.abs(start - stop) |
| 65 | ); |
| 66 | |
| 67 | // Optionally adjust the angles to counter linear scaling. |