Arc radius uglyness

in my arc i see a radial pixel jump,
( processing 3.4 , win7 )
any trick to avoid that?

int m = 150, r = 200;
float w =TAU/60;

void setup() {
  size(300, 300);
  noFill();
  strokeWeight(3);
}
void draw() {
  background(0, 100, 100);
//  translate(width/2, height/2);
//  rotate(-HALF_PI);
  stroke(0);
  ellipse (m, m, r, r);
  stroke(255);
  arc(m, m, r, r, -HALF_PI, -HALF_PI+w*second());
}

1 Like

That’s a tricky problem. I’m not too versed in getting per-pixel accuracy with Processing, but I can give you a suggestion:
You could have your 'inner" layed down first, and “reveal” it by slowly erasing a ring on top, held in a separate PGraphic.

I’m sure there’s a better way, but that’s just off the top of my head.

There’s also this snippet from the arc() reference:

In some cases, the arc() function isn’t accurate enough for smooth drawing. For example, the shape may jitter on screen when rotating slowly. If you’re having an issue with how arcs are rendered, you’ll need to draw the arc yourself with beginShape() / endShape() or a PShape .

2 Likes

ok, thanks,
from your idea i come up with that 2 versions:

  • -a- make a background colored circle inside and outside, what makes the
    white jittering arc smaller and the jitter is covered
  • -b- make a black circle, and a smaller white circle and a medium black
    backward running clock ( covering the white circle)
    as that black (anti clock wise ) arc is smaller as the black circle, its jitter is not visible.
int m = 150, r = 200;
float w =TAU/60;
int bar = 8;
color bg = color(0, 100, 100);
boolean blackclock = false, coverjitter = false; //true;

void setup() {
  size(300, 300);
  noFill();
  println("use key [c] for cover jitter; key [n] for black clock over white circle");
}

void draw() {
  background(bg);
  translate(width/2, height/2);
  rotate(-HALF_PI);
  stroke(0);
  strokeWeight(bar);
  ellipse (0, 0, r, r);
  stroke(255);
  strokeWeight(bar);
  if (blackclock) {
    stroke(255);
    strokeWeight(bar/2);
    ellipse (0, 0, r, r);
    strokeWeight(bar-1);
    stroke(0);
    arc(0, 0, r, r, w*(second()), TAU);
  } else {
    arc(0, 0, r, r, 0, w*second());
  }
  if (coverjitter) {
    stroke(bg);                    // cover color = background
    strokeWeight(bar/2);           // make 2 smaller cover circles / inside and outside
    ellipse (0, 0, r-bar, r-bar);
    ellipse (0, 0, r+bar, r+bar);
  }
}

void keyPressed() {
  if ( key == 'c' ) { 
    coverjitter = !coverjitter; 
    println("cover: "+coverjitter);
  }
  if ( key == 'n' ) { 
    blackclock = !blackclock;
    if (blackclock) { 
      coverjitter = false;
    }
    println("negativeclock: "+blackclock);
  }
}

2 Likes

An important thing to realize here is that this isn’t just an arc vs. ellipse inconsistency – the pixel locations of the arc stroke aren’t stable when compared to itself at different degrees of progress. See here:

int m = 150, r = 200;
float w =TAU/60;

void setup() {
  size(300, 300);
  noFill();
  strokeWeight(3);
}
void draw() {
  background(0, 100, 100);
  stroke(0);
  arc(m, m, r, r, -HALF_PI, -HALF_PI+w*60); // arc vs arc
  stroke(255);
  arc(m, m, r, r, -HALF_PI, -HALF_PI+w*second());
}

So you can’t use the arc stroke for pixel-perfect animation.

The most stable and reliable way to do this is to use a mask(). The mask is, by definition, a set of pixels. Cut out your ring with the mask, then use a filled arc to flood the mask background, and your ring cutout will always be pixel perfect. This is a general purpose method that works with any kind of weirdly shaped animated progress – an arc, dial, ramp, bar gauge, or weird lozenge-shaped readouts a-la Star Trek, et cetera.

2 Likes