Reuleaux polygon creation function on HTML 5 canvas
I am working on a project to develop systematic artwork using HTML 5 canvas. To make my artwork more organic and varied, I wanted to have a function that created reuleaux polygons. I think there might be a way to convert my function draw_sharp_polygon(center_position, radius, number_of_sides, regular, anticlockwise)
to the function I want, but I'm not sure how. Do I have to use a large number of functions, context.lineTo()
or could I use the function in some way context.arcTo()
?
function draw_sharp_polygon(center_position, radius, number_of_sides, regular, anticlockwise)
{
if(typeof center_position == 'undefined')
center_position = new Position();
if(typeof radius == 'undefined')
radius = dice_roll(diagonal);
if(typeof number_of_sides == 'undefined' || number_of_sides < 3)
number_of_sides = dice_roll(10);
if(typeof regular == 'undefined')
regular = coin_toss();
if(typeof anticlockwise == 'undefined')
anticlockwise = coin_toss();
context.moveTo(center_position.x + radius, center_position.y)
if(regular)
{
var circular_angle_division = (Math.PI * 2)/number_of_sides;
circular_angle_division = anticlockwise ? -1 * circular_angle_division : circular_angle_division;
for(var i = 1; i < number_of_sides; i++)
{
context.lineTo(radius * Math.cos(circular_angle_division * i),radius * Math.sin(circular_angle_division * i));
}
}
else
{
var amount_of_circle_taken = 0;
var direction = anticlockwise ? -1 : 1;
var sides_left = number_of_sides;
for(var i = 1; i < number_of_sides; i++)
{
if(i < number_of_sides -1)
{
var circular_angle_division = get_random_value(1, (((Math.PI * 2) - amount_of_circle_taken)/number_of_sides*(sides_left / 2)));
amount_of_circle_taken += circular_angle_division;
}
else
{
var circular_angle_division = (Math.PI * 2) - amount_of_circle_taken;
}
context.lineTo(radius * Math.cos(direction * circular_angle_division * i),radius * Math.sin(direction * circular_angle_division * i));
}
}
}
This is what I have for my flat, tight polygons. I was wondering if reuleaux could be used context.arcTo()
instead context.lineTo()
to create polygons.
I was about to post an example of a Reuleaux triangle, but I don't have enough reputation. However, there is a great example on Wikipedia.
PS I don't use jQuery in any of my personal projects, but I feel like most of them could become part of a separate javascript library. So please don't answer jQuery.
source to share
The tangent point required for arcTo()
is actually on the circle, halfway between the endpoints of the arc. The required radius could be calculated using:
reuleaux_radius = radius * sqrt(2 + 2*cos(pi / number_of_sides))
which is equivalent
reuleaux_radius = radius * sqrt(2 + 2*cos(angle2 - angle1))
Complete code:
var taget = document.getElementById('target');
var context = target.getContext('2d');
var sides = 3;
var radius = 100;
var center = new Position(150,150);
// normal polygon
context.beginPath();
draw_sharp_polygon(center, radius, sides);
context.strokeStyle = 'silver';
context.stroke();
// circle
context.beginPath();
context.arc(center.x, center.y, radius, 0, 2*Math.PI, false);
context.strokeStyle = 'silver';
context.stroke();
// reuleaux polygon
context.beginPath();
draw_reuleaux_polygon(center,radius,sides);
context.strokeStyle = 'black';
context.stroke();
function Position(x, y)
{
this.x = x || 0;
this.y = y || 0;
}
function draw_reuleaux_polygon(center_position, radius, number_of_sides)
{
if(typeof center_position == 'undefined')
throw new Error("center_position not defined");
if(typeof radius == 'undefined')
throw new Error("radius not defined");
if(typeof number_of_sides == 'undefined' || number_of_sides < 3)
throw new Error("number_of_sides not defined");
context.moveTo(center_position.x + radius, center_position.y);
for (var index1 = 0; index1 < number_of_sides; index1++)
{
// point 1 = arc start
// point 2 = tangent intersection
// point 3 = arc end
var index2 = (index1 + 0.5) % number_of_sides;
var index3 = (index1 + 1) % number_of_sides;
var angle1 = index1*2*Math.PI/number_of_sides;
var angle2 = index2*2*Math.PI/number_of_sides;
var angle3 = index3*2*Math.PI/number_of_sides;
var p1 = new Position(center_position.x + radius*Math.cos(angle1), center_position.y + radius*Math.sin(angle1));
var p2 = new Position(center_position.x + radius*Math.cos(angle2), center_position.y + radius*Math.sin(angle2));
var p3 = new Position(center_position.x + radius*Math.cos(angle3), center_position.y + radius*Math.sin(angle3));
var reuleaux_radius = radius*Math.sqrt(2 + 2*Math.cos(Math.PI/number_of_sides));
context.arcTo(p2.x, p2.y, p3.x, p3.y, reuleaux_radius);
}
context.closePath();
}
function draw_sharp_polygon(center_position, radius, number_of_sides)
{
if(typeof center_position == 'undefined')
throw new Error("center_position not defined");
if(typeof radius == 'undefined')
throw new Error("radius not defined");
if(typeof number_of_sides == 'undefined' || number_of_sides < 3)
throw new Error("number_of_sides not defined");
context.moveTo(center_position.x + radius, center_position.y);
var circular_angle_division = (Math.PI * 2)/number_of_sides;
for(var i = 1; i < number_of_sides; i++)
{
var x = center_position.x + radius * Math.cos(circular_angle_division * i);
var y = center_position.y + radius * Math.sin(circular_angle_division * i);
console.log(i,x,y);
context.lineTo(x,y);
}
context.closePath();
}
<canvas id="target" width="300" height="300"></canvas>
source to share