I’d like to create a shape that is, in essence, two, uniform concentric arcs connected by lines (radius segments) so that I can fill them individually. I’ve come close to doing it with Bezier curves but it’s still not right. In Illustrator I see how the control points are configured to create the arc but I can’t seem to duplicate it in P5. I’ve attached a screenshot from Illustrator to depict the scenario. Maybe curveVertex would be easier?? Thanks for any insights!
Hello,
Consider making it with just vertex().
Processing example:
void setup()
{
size(200, 200);
translate(width/2, height/2);
fill(128);
beginShape();
vertex(0, 40);
vertex(0, 50);
vertex(50*cos(TAU/8), 50*sin(TAU/8));
vertex(50, 0);
vertex(40, 0);
vertex(40*cos(TAU/8), 40*sin(TAU/8));
endShape(CLOSE);
noFill();
circle(0, 0, 90);
}
You can generate all the missing points with a for() loop and some trigonometry:
Trigonometry Primer \ Processing.org
:)
Hello!,
Now that’s a fascinating idea I had not considered!! Thank you! I’ll give that a shot.
Worked like a charm. Thanks again.
Hi, if you still want to you brazier curve, what you wanna draw is a half circle.
Look online for how to approximate circle with bezier curves and it will gives you the values to input.
Hi @psemme ,
To draw an arc with the bezier()
function, you just need to indicate the control points as you did in your picture from the vector based drawing software :
You have two bezier curves (from left to right) that use the same middle point as anchor point.
The way the control points are computed is based on the ratio of the radius multiplied by the radius of the arc, see this animation :
So I found that to have an approximate circle shape, the ratio should be close to 0.555
, don’t ask me why (it can surely be computed with math)
The only downside to this is that you can’t really fill two bezier curves without using beginShape
and endShape
as @glv wrote.
Note that you could have done it simply using the arc()
function.
Here is the code (very verbose) to make that in Processing :
Unfold me ;)
void bezierArc(float x, float y, float diameter, float rotation, float strength, boolean debug) {
float radius = diameter / 2.0;
PVector leftAnchorPoint = new PVector(-radius, 0);
PVector leftControlPoint = new PVector(-radius, -radius * strength);
PVector middleAnchorPoint = new PVector(0, -radius);
PVector middleControlPointLeft = new PVector(-radius * strength, -radius);
PVector middleControlPointRight = new PVector(radius * strength, -radius);
PVector rightAnchorPoint = new PVector(radius, 0);
PVector rightControlPoint = new PVector(radius, -radius * strength);
// Apply transform
pushMatrix();
translate(x, y);
rotate(rotation);
// Bezier curves
stroke(0);
strokeWeight(4);
noFill();
// Left portion
stroke(#80C9A5);
bezier(leftAnchorPoint.x, leftAnchorPoint.y,
leftControlPoint.x, leftControlPoint.y,
middleControlPointLeft.x, middleControlPointLeft.y,
middleAnchorPoint.x, middleAnchorPoint.y);
// Right portion
stroke(#DD79DE);
bezier(middleAnchorPoint.x, middleAnchorPoint.y,
middleControlPointRight.x, middleControlPointRight.y,
rightControlPoint.x, rightControlPoint.y,
rightAnchorPoint.x, rightAnchorPoint.y);
if (debug) {
// Display handles
stroke(#EA911C);
strokeWeight(3);
line(leftAnchorPoint.x, leftAnchorPoint.y, leftControlPoint.x, leftControlPoint.y);
line(middleAnchorPoint.x, middleAnchorPoint.y, middleControlPointLeft.x, middleControlPointLeft.y);
line(middleAnchorPoint.x, middleAnchorPoint.y, middleControlPointRight.x, middleControlPointRight.y);
line(rightAnchorPoint.x, rightAnchorPoint.y, rightControlPoint.x, rightControlPoint.y);
// Points
float pointSize = 10;
// Control points
strokeWeight(pointSize);
point(leftControlPoint.x, leftControlPoint.y);
point(middleControlPointLeft.x, middleControlPointLeft.y);
point(middleControlPointRight.x, middleControlPointRight.y);
point(rightControlPoint.x, rightControlPoint.y);
// Anchor points
strokeWeight(4);
fill(255);
circle(leftAnchorPoint.x, leftAnchorPoint.y, pointSize + 0.1);
circle(middleAnchorPoint.x, middleAnchorPoint.y, pointSize + 0.1);
circle(rightAnchorPoint.x, rightAnchorPoint.y, pointSize + 0.1);
}
popMatrix();
}
float time = 0;
void setup() {
size(300, 300);
}
void draw() {
background(255);
float strength = (cos(time) + 1) / 2.0;
float circleSize = width * 0.8;
translate(width / 2, height / 2);
// Display reference circle
noFill();
stroke(#8395F5, 100);
strokeWeight(6);
circle(0, 0, circleSize);
// Display rectangle
rectMode(CENTER);
stroke(100, 100);
strokeWeight(3);
square(0, 0, circleSize);
// Display arcs
bezierArc(0, 0, circleSize, 0, strength, true);
bezierArc(0, 0, circleSize, PI, strength, true);
// Display ratio text
textAlign(CENTER, CENTER);
textSize(20);
fill(100);
text(strength, 0, 0);
time += 0.02;
}
I made this post to explain you how you can effectively use bezier curves to make your own arc function (half circle) but you can have fun with this by animating the parameters :
And another way which overlays shapes with different strokeWidth():
I used:
strokeCap(PROJECT); // This seemed to provide square ends
This easy to do with arc() as well:
:)
Thanks jb4x - I looked online and saw some entries on what values to use. I’ll give it a try. Thx again.
Hi Joseph - that’s a seriously thorough answer! Thank you! I like the solution from @giv because I can both fill the shape and then manipulate the vertices further in another step. But you’ve opened my eyes on the possibilities of animating beziers! Thanks again.
Thanks @giv - I used that approach earlier and it works great, but I like the option of playing with the vertices that make up the original shape, in some later step, and the strokeWeight approach doesn’t allow that. Thanks for continuing to think up answers!