Symmetry Cycloid Patterns

Symmetry Cycloids_v.08A
1
1
1
1

About Project:

This project started as a process to explore Epicycloids—visualizing how a point on a rolling and orbiting circle traces its path around another circle. I also included Hypocycloids, which work on the same principle, but with a rolling circle inside the central circle.

As I developed the project, I realized that focusing on precision made the results more predictable, but also less interesting. To make it more fun, as a hobby, not an assignment, I drew inspiration from intricate patterns based on simple symmetry, repetition, and rotation from traditional Thai ornaments. Adding a repetition feature transformed the curves, making them more dynamic and aligned with the qualities found in traditional arts and crafts.

Overview:

This project uses p5.js and JavaScript to create interactive visualizations of epicycloids and hypocycloids. Users can switch between these curve types and adjust settings such as the number of repetitions, animation speed, and the size of the central and orbiting circles. The repetition feature, along with the dynamic resizing of the circles' radii during orbiting, adds layers of symmetry, turning basic geometric shapes into intricate and less predictable patterns.

 

Share:

Facebook
LinkedIn

User Guide:

Select the Curve Type:

  • Epicycloid: Click the "EPICYCLOID" button to generate patterns where the tracing point moves along the outside of a rolling circle.
  • Hypocycloid: Click the "HYPOCYCLOID" button to generate patterns where the tracing point moves along the inside of a rolling circle.

Clear the Curve Trace:

  • Clear: Click the "CLEAR" button to remove all previous traces and start drawing fresh curves. 

Adjust the Parameters:

  • Number of Repetitions: Control the number of repeated patterns around the central circle.
  • Speed: Adjust the speed at which the curves are drawn. Set the speed value to 0 to pause the drawing. Increase the speed again to resume.
  • Radius (Central): Change the size of the fixed central circle.
  • Radius (Orbit): Modify the size of the rolling orbit circle.

 

This work is licensed under CC BY-NC-SA 4.0

 

เอพิไซคลอยด์กับไฮโพไซคลอยด์: 

เมื่อสุดสัปดาห์ที่ผ่านมาผมลองทำความเข้าใจเส้นโค้งเอพิไซคลอยด์ (Epicycloid) และไฮโพไซคลอยด์ (Hypocycloid) โดยได้แรงบันดาลใจจากของเล่นหน้าโรงเรียนสมัยเด็ก ๆ ที่เป็นชุดวงกลมพลาสติกเจาะรูให้วางปากกาและหมุนไปตามเฟืองจนเกิดเป็นภาพเรขาคณิตต่าง ๆ จากการหมุน หรือที่เรียกว่าสไปโรกราฟ (Spirograph) ผมลองใช้แนวคิดนี้เป็นจุดเริ่มต้นของการทำความเข้าใจเรขาคณิตจากการหมุนของวงกลมสองวงขึ้นมา

เส้นโค้งเอพิไซคลอยด์เกิดจากการที่วงกลมวงหนึ่งหมุนรอบตัวเองไปพร้อมกับโคจรรอบเส้นรอบวงของวงกลมอีกวงหนึ่ง โดยจุดที่เราเลือกบนวงกลมวงที่โคจรนั้นจะลากเส้นโค้งตามการหมุน เกิดเป็นแพทเทิร์นของเส้นโคงที่มาจากความสัมพันธ์ของวงกลมสองวง ส่วนเส้นโค้งไฮโพไซคลอยด์นั้นเกิดขึ้นในลักษณะเดียวกัน แต่เปลี่ยนจากการหมุนและโคจรภายนอกตามเส้นรอบวง ไปเป็นการหมุนและโคจรภายในวงกลมอีกวงหนึ่งแทน

พอทำไปสักพัก ผมเลยลองเพิ่มความเป็นไปได้ในการสร้างการย้ำหรือซ้ำเส้นโค้งที่สมมาตรกัน โดยใช้แนวคิดจากศิลปหัตถกรรมพื้นบ้าน ซึ่งมักสร้างแพทเทิร์นจากการย้ำซ้ำสานด้วยการหมุน ทำให้เกิดความซับซ้อนจากความเรียบง่าย ผมทดลองเพิ่มฟังชั่นให้ผู้ใช้งานสามารถปรับค่าได้ เช่น จำนวนการซ้ำของวงกลมที่หมุนรอบ (Repetitions), ความเร็ว (Speed) และ ขนาดของวงกลม (Radius) ของวงกลมหลักและวงกลมที่หมุนรอบ

หลายครั้งที่ผมได้ยินว่าลวดลายในศิลปะไทยนั้นมาจากธรรมชาติ สำหรับผมคิดว่ารูปร่างรูปทรงในธรรมชาติเองก็พัฒนามาจากสมการทางคณิตศาสตร์ที่ขึ้นต้นอย่างเรียบง่าย และมีวิวัฒนาการไปสู่ความซับซ้อนผ่านการย้ำและซ้ำในมุมที่ต่างกันไปเรื่อย ๆ โปรเจคนี้จึงเป็นการใช้เวลาทำความเข้าใจเรขาคณิตทั้งในทางคณิตศาสตร์กับความงาม ที่ผมก็ทำแล้วก็ชอบเลยอยากเก็บบันทึกไว้ หวังว่าจะมีประโยชน์สำหรับผู้ที่สนใจในการผสมผสานเรขาคณิตกับศิลปะบ้างไม่มากก็น้อยครับ 

ขอบคุณครับ

Saranont Limpananont

2024.08.27

*This program was made using p5.js, a JavaScript library for creative coding.


Appendix A: Epicycloids and Hypocycloids

Epicycloids and hypocycloids are both types of roulette curves generated by the path of a point on a circle as it rolls around another circle.

Epicycloids:

These are curves traced by a point on the circumference of a circle that rolls without slipping around the outside of another circle. The mathematical formula for the coordinates  (x, y) of an epicycloid is given by:

 x(\theta) = (R + r) \cdot \cos(\theta) - d \cdot \cos\left(\frac{R + r}{r} \cdot \theta\right)
 
 y(\theta) = (R + r) \cdot \sin(\theta) - d \cdot \sin\left(\frac{R + r}{r} \cdot \theta\right)

Hypocycloids:

These are similar to epicycloids but are generated when the circle rolls inside another circle. The formula is:

 x(\theta) = (R - r) \cdot \cos(\theta) + d \cdot \cos\left(\frac{R - r}{r} \cdot \theta\right)
 
 y(\theta) = (R - r) \cdot \sin(\theta) - d \cdot \sin\left(\frac{R - r}{r} \cdot \theta\right)

  • is the radius of the central circle.
  •  r is the radius of the orbit circle.
  •  d  is the distance from the center of the rolling circle to the tracing point.
  •  \theta is the angle of rotation.
Algorithm Implementation:

Below is the part of the code that translates the mathematical formulas into visual patterns:

function drawCycloidalPattern() {
    // Smoothly transition the radii using linear interpolation
    centralRadius = lerp(centralRadius, targetCentralRadius, lerpSpeed);
    orbitRadius = lerp(orbitRadius, targetOrbitRadius, lerpSpeed);
    distanceFromOrbitCenterToTracingPoint = orbitRadius;

    // Handle transition between Epicycloid and Hypocycloid modes
    let rollingCircleDistance;
    let rotationRatio;
    if (isTransitioning) {
        transitionProgress += 1 / transitionDuration;
        if (transitionProgress >= 1) {
            transitionProgress = 1;
            isTransitioning = false;
            restoreSpeed();
        }
        rollingCircleDistance = lerp(
            initialRollingCircleDistance,
            isHypocycloid 
                ? centralRadius - orbitRadius 
                : centralRadius + orbitRadius,
            transitionProgress
        );
        rotationRatio = isHypocycloid 
            ? (centralRadius - orbitRadius) / orbitRadius 
            : (centralRadius + orbitRadius) / orbitRadius;
    } else {
        rollingCircleDistance = isHypocycloid 
            ? centralRadius - orbitRadius 
            : centralRadius + orbitRadius;
        rotationRatio = rollingCircleDistance / orbitRadius;
    }

    // Calculate the rolling circle’s center position
    let rollingCircleCenterX = rollingCircleDistance * cos(theta);
    let rollingCircleCenterY = rollingCircleDistance * sin(theta);

    // Adjust for Hypocycloid direction
    let rotationDirection = isHypocycloid ? -1 : 1;

    // Calculate the tracing point’s position
    let tracingPointX = rollingCircleCenterX 
        + distanceFromOrbitCenterToTracingPoint 
        * cos(rotationDirection * theta * rotationRatio);
    let tracingPointY = rollingCircleCenterY 
        + distanceFromOrbitCenterToTracingPoint 
        * sin(rotationDirection * theta * rotationRatio);

    // Draw circles, lines, and tracing point
    centralCircle.draw();
    orbitCircle.draw(rollingCircleCenterX, rollingCircleCenterY);
    orbitRadiusLine.draw(rollingCircleCenterX, rollingCircleCenterY, tracingPointX, tracingPointY);
    tracingPoint.draw(tracingPointX, tracingPointY);
    centralRadiusLine.draw(rollingCircleCenterX, rollingCircleCenterY);

    // Add and draw the traced curve
    if (isTracingEnabled) {
        tracedCurve.addPoint(createVector(tracingPointX, tracingPointY));
    }
    tracedCurve.draw();
}

Image courtesy of Saranont Limpananont