We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › drawing rings with alpha value and off-centre hole
Page Index Toggle Pages: 1
drawing rings with alpha value and off-centre hole (Read 855 times)
drawing rings with alpha value and off-centre hole
Sep 12th, 2008, 2:33am
 
This seems like it should be simple, but I just can't get it. I'm trying to get Processing to draw rings something like these: http://infosthetics.com/archives/today_mobile_phone2.jpg

I want simple circular rings, semi-transparent with the hole in the ring off centre. I've tried:
- the Geomerative library but it's rings render oddly (zig-zag lines in what should be a solid fill) so I didn't push too far there.
- creating an ellipse with no fill and a heavy strokeWeight. Looks great, but obviously the hole is centred.
- considered overlapping two rings create with the heavy stroke ellipse method, one for the outer circle and one to provide the off-centre hole. Seems like the alpha is the downfall here though, as they it's visually obvious that they two rings and not one.
- Right now I'm seeing if blend() can help me, here's the latest code I have, obviously not there yet as the hole in the blue ring ought to let the red ring show through.

Any suggestions much appreciated.

background(255);
size(700,700);
smooth();

strokeWeight(30);
stroke(0);
fill(0,0,0,0);
ellipse(400,400,100,100);

noStroke();
fill(255,0,0,200);
ellipse(100,100,150,150);

// blend(x, y, width, height, dx, dy, dwidth, dheight, MODE)
blend(360,360,80,80,50,50,80,80,ADD);

noStroke();
fill(0,0,255,200);
ellipse(150,150,200,200);

blend(360,360,80,80,100,100,80,80,ADD);
Re: drawing rings with alpha value and off-centre
Reply #1 - Sep 12th, 2008, 10:49am
 
i did something similar for the op-art handball thing:

http://www.koogy.clara.co.uk/processing/riley1/

i used 72-edge polygons rather than circles and drew them myself as quads that joined the outer and inner rings. not sure how it would work with transparency though (processing renders quads as two triangles at times)
Re: drawing rings with alpha value and off-centre
Reply #2 - Sep 12th, 2008, 11:14am
 
How about something like this:

Quote:
void setup()
{
  size(400,400);
  smooth();
  noStroke();
}

void draw()
{
  background(255);

  fill(180,50,50,100);
  ring(0.5*width,0.5*height/2,80, 0.4*width,0.3*height,30);
 
  fill(50,50,180,100);
  ring(0.7*width,0.4*height,110, 0.75*width,0.4*height,60);
}

// Create a ring by drawing an outer cicle clockwise and an inner circle anticlo
ckwise.

void ring(float cx1, float cy1, float r1, float cx2, float cy2, float r2)
{
  beginShape();
   buildCircle(cx1,cy1,r1,true);
   buildCircle(cx2,cy2,r2,false);
  endShape();
}

// Creates a circle using spline curves. Can be drawn either clockwise
// which creates a solid circle, or anticlockwise that creates a hole.
void buildCircle(float cx, float cy, float r, boolean isClockwise)
{
  int numSteps = 10;
  float inc = TWO_PI/numSteps;
     
  if (isClockwise)
  {
    // First control point should be penultimate point on circle.
    curveVertex(cx+r*cos(-inc),cy+r*sin(-inc));
    
    for (float theta=0; theta<TWO_PI-0.01; theta+=inc)
    {
      curveVertex(cx+r*cos(theta),cy+r*sin(theta));
    }
    curveVertex(cx+r,cy);
    
    // Last control point should be second point on circle.
    curveVertex(cx+r*cos(inc),cy+r*sin(inc));
    
    // Move to start position to keep curves in circle.
    vertex(cx+r,cy);
  }
  else
  {
    // Move to start position to keep curves in circle.
    vertex(cx+r,cy);
    
    // First control point should be penultimate point on circle.
    curveVertex(cx+r*cos(inc),cy+r*sin(inc));
        
    for (float theta=TWO_PI; theta>0.01; theta-=inc)
    {
      curveVertex(cx+r*cos(theta),cy+r*sin(theta));
    }
    curveVertex(cx+r,cy);
     
    // Last control point should be second point on circle.
    curveVertex(cx+r*cos(TWO_PI-inc),cy+r*sin(TWO_PI -inc));
  }  
}


Uses curveVertex to draw a smooth circle with about 12 vertices. Note though that only works if you use noStroke() since the inner and outer circles of each ring are joined with a line. Transparency works fine.

I don't know of any way in Processing to effect a 'moveto' inside beginShape() / endShape(). It would be very helpful if there was.
Re: drawing rings with alpha value and off-centre
Reply #3 - Sep 12th, 2008, 3:46pm
 
Thank you very much for the responses. The code that Jo provided does exactly what I was looking for.
Re: drawing rings with alpha value and off-centre
Reply #4 - Sep 12th, 2008, 4:32pm
 
A rule of 2D graphics states that to draw holes in an object, the hole must be drawn in the reverse order of the outer shape.
Ie. for a circle, you draw the outer diameter clockwise, and the inner one counter-clockwise. Or the reverse.
That said, how to draw a circle in a defined direction? I recently discovered that Java draws them using four CubicCurves, our Bézier curves, with a ratio between control vector and radius of 0.552.
I tried and indeed it matches closely the drawing of an ellipse.

The remainder was then quite simple to do. Smiley It seems to work well.

Code:
// Clockwise
void drawCircleCW(float x, float y, float w, float h)
{
// Java draws circles using four cubic curves too, with ratio of length of control vector
// against radius of 0.552. I compute the complement of this ratio for convenience.
float l = 1 - 0.552;
float hw = w / 2, hh = h / 2;
float lx = l * hw, ly = l * hh;
// Assume here default CENTER mode
x -= hw; y -= hh;

vertex(x, y + hh); // Left
bezierVertex(x, y + ly,
x + lx, y,
x + hw, y); // Top
bezierVertex(x + w - lx, y,
x + w, y + ly,
x + w, y + hh); // Right
bezierVertex(x + w, y + h - ly,
x + w - lx, y + h,
x + hw, y + h); // Bottom
bezierVertex(x + lx, y + h,
x, y + h - ly,
x, y + hh); // Back to left
}

// Counter Clockwise
void drawCircleCCW(float x, float y, float w, float h)
{
float l = 1 - 0.552;
float hw = w / 2, hh = h / 2;
float lx = l * hw, ly = l * hh;
// Assume here default CENTER mode
x -= hw; y -= hh;

vertex(x, y + hh); // Left
bezierVertex(x, y + h - ly,
x + lx, y + h,
x + hw, y + h); // Bottom
bezierVertex(x + w - lx, y + h,
x + w, y + h - ly,
x + w, y + hh); // Right
bezierVertex(x + w, y + ly,
x + w - lx, y,
x + hw, y); // Top
bezierVertex(x + lx, y,
x, y + ly,
x, y + hh); // Back to left
}

// Draw a ring, assuming it is circular (not an ellipse),
// but accepting that the internal circle isn't centered on the external one
void drawRing(
float xx, float xy, float xd, // Center of external circle and its diameter
float ix, float iy, float id) // Center of internal circle and its diameter
{
beginShape();
drawCircleCCW(xx, xy, xd, xd);
drawCircleCW(ix, iy, id, id);
endShape();
}

void setup()
{
size(500, 500);
noLoop();

noStroke();
background(222);
// To verify it fits to a circle
fill(#FF0000);
ellipse(width/2, height/2, 200, 200);
// Draw test ring
fill(0x8800EE00);
drawRing(width/2, height/2, 200,
width/2, height/2, 100);
// Draw some others
fill(0x440000EE);
for (int i = 0; i < 5; i++)
{
float rxd = width / random(1.5, 5);
float rxx = random(rxd / 2, width - rxd / 2);
float rxy = random(rxd / 2, height - rxd / 2);
float rid = rxd / random(2, 4);
float rix = rxx + rid * random(-0.9, 0.9) / 4;
float riy = rxy + rid * random(-0.9, 0.9) / 4;
drawRing(rxx, rxy, rxd, rix, riy, rid);
}
}
Page Index Toggle Pages: 1