Skip to content

Instantly share code, notes, and snippets.

@bohnacker
Last active April 29, 2024 08:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bohnacker/c5decf3f09cf365f2341ebf24a343f77 to your computer and use it in GitHub Desktop.
Save bohnacker/c5decf3f09cf365f2341ebf24a343f77 to your computer and use it in GitHub Desktop.
Calculate positions of dots to draw a filled circle made of dots. This version creates rings in a more advanced way, so that the outer ring is always completely filled.
// Calling this function will return a function that gives you the position of the dot at an index.
// You must also pass the total number of dots of the circle to this function to calculate correctly.
//
// This version creates rings in a more advanced way, so that the outer ring is always completely filled.
// This is made as a closure so that the array of positions is only calculated once.
//
// Usage:
// let getDotPosition = initCircleOfDots_AdvancedRings();
// let p = getDotPosition(50, 100);
//
// This will return a point in the format { x: 4.0618, y: -1.0683 }
// The distance between the dots is approximately 1, so you probably have to scale the positions.
function initCircleOfDots_AdvancedRings() {
let dotsPerRingArray = [];
dotsPerRingArray.push([1]);
dotsPerRingArray.push([2]);
let lastSum = 2;
let r = 0;
// scale the dots a little bit to make the distance approximately 1
let adjustmentFactor = 1.05;
function calculateDotsPerRing(count) {
if (count <= dotsPerRingArray.length) {
return dotsPerRingArray[count - 1];
}
// console.log("calculate new rings for " + count);
// slowly grow radius of the outer ring to fit one more dot on the rings
while (dotsPerRingArray.length < count) {
let sum = 0;
let counts = [];
// radiusses of all the rings
for (let rr = r; rr >= 0; rr -= 1) {
// how many dots fit on the ring
let n = Math.floor(Math.PI * 2 * rr) + 1;
sum += n;
counts.unshift(n);
}
if (sum > lastSum) {
//console.log(counts);
//console.log(sum);
// two dots in the middle doesn't look good, so we change it to 3 dots and remove one from the outer ring
if (counts[0] == 2) {
counts[0] = 3;
counts[counts.length - 1] -= 1;
}
// six dots in the middle doesn't look good, so we change it to 5 dots and add one in the middle
if (counts[0] == 6) {
counts[0] = 5;
counts.unshift(1);
}
// 7 dots in the middle doesn't look good, so we change it to 6 dots and add one in the middle
if (counts[0] == 7) {
counts[0] = 6;
counts.unshift(1);
}
dotsPerRingArray.push(counts);
lastSum = sum;
}
r += 0.001;
}
// console.log(dotsPerRingArray);
return dotsPerRingArray;
}
let actCount = 0;
let actDotArray = [];
// This function will be returned by initCircleOfDots_Rings.
// Call this function to get the position of the dot at an index where count is the total number of dots.
// This is made as a closure so that the array of positions is only calculated once.
function getDotPosition(index, count) {
if (count != actCount) {
actCount = count;
actDotArray = calculateDotsPerRing(count);
} else {
if (index < actDotArray.length) {
return actDotArray[index];
}
}
// console.log("calculate dots for " + count);
actDotArray = [];
if (dotsPerRingArray[count - 1]) {
let dpr = dotsPerRingArray[count - 1];
let innerRadius = 0;
if (dpr[0] == 2) innerRadius = 0.5;
if (dpr[0] > 2) innerRadius = dpr[0] / (Math.PI * 2);
let outerRadius = Math.sqrt(count) / 2;
if (dpr.length == 1 && dpr[0] > 1) innerRadius = outerRadius;
let startAngle = 0;
for (let r = 0; r < dpr.length; r++) {
let n = dpr[r];
let radius = innerRadius;
if (dpr.length > 1) {
radius = (r / (dpr.length - 1)) * (outerRadius - innerRadius) + innerRadius;
}
startAngle += Math.PI / n;
for (let i = 0; i < n; i++) {
let angle = startAngle + (i * Math.PI * 2) / n;
let x = Math.cos(angle) * radius;
let y = Math.sin(angle) * radius;
actDotArray.push({ x: x * adjustmentFactor, y: y * adjustmentFactor });
}
}
}
return actDotArray[index];
}
return getDotPosition;
}
export { initCircleOfDots_AdvancedRings };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment