๐Ÿ”ง โ”  6. Extension ํ•จ์ˆ˜ โ€” OPENRNDR ์Šคํƒ€์ผ์˜ ํ•ต์‹ฌ

BamgasiJMยท2026๋…„ 9์›” 28์ผ

OPENRNDR

๋ชฉ๋ก ๋ณด๊ธฐ
6/17
post-thumbnail

๊ทธ๋ฆฌ๊ธฐ ๋ช…๋ น์„ Drawer ๊ฐ์ฒด๋กœ ํ˜ธ์ถœํ•˜๋‹ค ๋ณด๋ฉด ๊ฒฉ์ž๋‚˜ ๋ฐฉ์‚ฌํ˜• ๋ฐฐ์น˜์ฒ˜๋Ÿผ ๊ฐ™์€ ๊ณ„์‚ฐ์ด ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.

extend {
    drawer.clear(ColorRGBa.BLACK)
    drawer.circle(400.0, 400.0, 100.0)
}

๊ฒฉ์ž๋Š” ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ์ง์ ‘ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

extend {
    for (x in 0 until 10) {
        for (y in 0 until 10) {
            val px = x * 80.0
            val py = y * 80.0
            drawer.circle(px, py, 20.0)
        }
    }
}

๊ฐ™์€ ๋ฐฐ์น˜ ๊ทœ์น™์„ ์—ฌ๋Ÿฌ ์ž‘ํ’ˆ์—์„œ ์“ด๋‹ค๋ฉด ๊ณ„์‚ฐ์„ ํ™•์žฅ ํ•จ์ˆ˜๋กœ ๋ฌถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

extend {
    drawer.grid(10, 10, 80.0, 20.0)
}

Drawer๋ฅผ ๋ฆฌ์‹œ๋ฒ„๋กœ ์„ ์–ธํ•œ ํ™•์žฅ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฉด drawer.grid(...)์ฒ˜๋Ÿผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ˜ธ์ถœ ๋ฌธ๋ฒ•์€ ๋ฉค๋ฒ„ ๋ฉ”์„œ๋“œ์™€ ๋น„์Šทํ•˜์ง€๋งŒ, Drawer ํด๋ž˜์Šค ์ž์ฒด์— ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.


Extension ํ•จ์ˆ˜๋ž€?

ํ™•์žฅ ํ•จ์ˆ˜๋Š” ๊ธฐ์กด ํƒ€์ž…์„ ๋ฆฌ์‹œ๋ฒ„๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ด ๊ทธ ํƒ€์ž…์˜ ๊ฐ’์—์„œ ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ํ˜ธ์ถœํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž…์˜ ์†Œ์Šค๋‚˜ ๋Ÿฐํƒ€์ž„ ๊ตฌ์กฐ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š์œผ๋ฉฐ, ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉค๋ฒ„๋„ ํ•ด๋‹น ์œ„์น˜์—์„œ ์›๋ž˜ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋ฒ”์œ„๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๋ฌธ๋ฒ•

// ์ •์ˆ˜ ํด๋ž˜์Šค์— ์ƒˆ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
fun Int.isEven(): Boolean {
    return this % 2 == 0
}

// ์‚ฌ์šฉ
val num = 10
println(num.isEven())  // true

๊ตฌ์กฐ:

fun ํด๋ž˜์Šค์ด๋ฆ„.๋ฉ”์„œ๋“œ์ด๋ฆ„(ํŒŒ๋ผ๋ฏธํ„ฐ): ๋ฐ˜ํ™˜ํƒ€์ž… {
    // this๋Š” ์ž๋™์œผ๋กœ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค
}

๋” ๋ณต์žกํ•œ ์˜ˆ์ œ

// String ํด๋ž˜์Šค์— "๋‹จ์–ด ๊ฐœ์ˆ˜ ์„ธ๊ธฐ" ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
fun String.wordCount(): Int {
    return this.split(" ").size
}

val text = "Hello World OPENRNDR"
println(text.wordCount())  // 3

ํ™•์žฅ ํ•จ์ˆ˜ ๋ณธ๋ฌธ์—์„œ this๋Š” ๋ฆฌ์‹œ๋ฒ„์ธ String ๊ฐ’์ž…๋‹ˆ๋‹ค. ํ™•์žฅ ํ•จ์ˆ˜๋Š” ์ •์ ์œผ๋กœ ํ•ด์„๋˜๋ฏ€๋กœ, ๊ฐ™์€ ๊ฐ์ฒด๋ผ๋„ ์ปดํŒŒ์ผ ์‹œ์ ์— ์•Œ๋ ค์ง„ ๋ณ€์ˆ˜ ํƒ€์ž…์— ๋”ฐ๋ผ ํ˜ธ์ถœ๋˜๋Š” ํ™•์žฅ ํ•จ์ˆ˜๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ ์žˆ์œผ๋ฉด ๋ฉค๋ฒ„๊ฐ€ ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค.


OPENRNDR์—์„œ์˜ Extension ํ•จ์ˆ˜

์™œ ์ค‘์š”ํ•œ๊ฐ€?

๊ทธ๋ฆฌ๊ธฐ์™€ ์ขŒํ‘œ ๊ณ„์‚ฐ์— ๋ฐ˜๋ณต๋˜๋Š” ํŒจํ„ด์„ ์ด๋ฆ„ ์žˆ๋Š” ํ•จ์ˆ˜๋กœ ๋ฌถ์œผ๋ฉด ํ˜ธ์ถœ๋ถ€์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋ชฉ์ ์„ ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

// 1๋‹จ๊ณ„: ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ ๋ฐœ๊ฒฌ
extend {
    // ๊ฒฉ์ž ํŒจํ„ด์„ ๋งค๋ฒˆ ์ด๋ ‡๊ฒŒ ์“ด๋‹ค
    for (x in 0 until 10) {
        for (y in 0 until 10) {
            drawer.circle(x * 80.0, y * 80.0, 20.0)
        }
    }
}

// 2๋‹จ๊ณ„: Extension ํ•จ์ˆ˜๋กœ ์ถ”์ƒํ™”
fun Drawer.grid(cols: Int, rows: Int, spacing: Double, radius: Double = 20.0) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, radius)
        }
    }
}

// 3๋‹จ๊ณ„: ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉ
extend {
    drawer.grid(10, 10, 80.0)
}

p5.js์™€์˜ ๋น„๊ต

p5.js: ๋ณ„๋„ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐฉ์‹

p5.js์—์„œ๋Š” ์ƒˆ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

function drawGrid(cols, rows, spacing) {
    for (let x = 0; x < cols; x++) {
        for (let y = 0; y < rows; y++) {
            circle(x * spacing, y * spacing, 20);
        }
    }
}

function draw() {
    background(0);
    drawGrid(10, 10, 80);
}

drawGrid๋Š” ์ „์—ญ ํ•จ์ˆ˜๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๋ฉด ํ•จ์ˆ˜ ์ด๋ฆ„๊ณผ ๊ทธ๋ฆฌ๊ธฐ ๋Œ€์ƒ์˜ ๊ด€๊ณ„๋ฅผ ์ž‘์„ฑ์ž๊ฐ€ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

OPENRNDR: ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ์‚ฌ์šฉ

fun Drawer.grid(cols: Int, rows: Int, spacing: Double) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, 20.0)
        }
    }
}

extend {
    drawer.grid(10, 10, 80.0)  // Drawer์˜ ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ!
}

ํ™•์žฅ ํ•จ์ˆ˜์˜ ๋ฆฌ์‹œ๋ฒ„ ํƒ€์ž…์ด Drawer์ด๋ฏ€๋กœ ํ˜ธ์ถœ๋ถ€์˜ drawer.grid(...)์—์„œ ๊ทธ๋ฆฌ๊ธฐ ๋Œ€์ƒ๊ณผ ํŒจํ„ด ํ•จ์ˆ˜์˜ ๊ด€๊ณ„๋ฅผ ํ•จ๊ป˜ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. grid๋Š” Drawer์˜ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ํ™•์žฅ ํ•จ์ˆ˜๊ฐ€ ์„ ์–ธ๋œ ํŒŒ์ผ์ด๋‚˜ ํŒจํ‚ค์ง€ ๋ฒ”์œ„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์‹ค์ „ ์˜ˆ์ œ 1: ๊ฒฉ์ž ๊ทธ๋ฆฌ๊ธฐ

// Extension ํ•จ์ˆ˜ ์ •์˜
fun Drawer.grid(
    cols: Int,
    rows: Int,
    spacing: Double,
    radius: Double = 20.0
) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, radius)
        }
    }
}

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.WHITE
        drawer.grid(12, 12, 60.0, 15.0)
    }
}

์‚ฌ์šฉ์˜ ํŽธ์˜์„ฑ:

  • drawer.grid(12, 12, 60.0, 15.0) ํ˜ธ์ถœ๋กœ ์ด์ค‘ ๋ฐ˜๋ณต๊ณผ ์ขŒํ‘œ ๊ณ„์‚ฐ์„ ์ˆจ๊น๋‹ˆ๋‹ค.
  • ๊ฐ„๊ฒฉ๊ณผ ๋ฐ˜์ง€๋ฆ„์„ ์ธ์ž๋กœ ๋ฐ”๊พธ์–ด ๊ฐ™์€ ๋ฐฐ์น˜ ๊ทœ์น™์„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ „ ์˜ˆ์ œ 2: ์›ํ˜• ๋ฐฐ์น˜

// ์ค‘์‹ฌ ์ฃผ์œ„์— ์›ํ˜•์œผ๋กœ ๋ฐฐ์น˜
fun Drawer.radialLayout(
    count: Int,
    distance: Double,
    radius: Double = 20.0,
    centerX: Double = 400.0,
    centerY: Double = 400.0
) {
    require(count > 0) { "count must be positive" }
    for (i in 0 until count) {
        val angle = TWO_PI * i / count
        val x = centerX + distance * cos(angle)
        val y = centerY + distance * sin(angle)
        circle(x, y, radius)
    }
}

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.PINK
        
        // ํ™”๋ฉด ์ค‘์•™์—์„œ 12๊ฐœ ์›์„ 150 ํ”ฝ์…€ ๊ฑฐ๋ฆฌ์— ๋ฐฐ์น˜
        drawer.radialLayout(12, 150.0, 15.0)
    }
}

์‹ค์ „ ์˜ˆ์ œ 3: ๋‚˜์„  ๊ทธ๋ฆฌ๊ธฐ

// ๋‚˜์„  ํŒจํ„ด
fun Drawer.spiral(
    count: Int,
    spacing: Double,
    rotation: Double = 0.0,
    centerX: Double = 400.0,
    centerY: Double = 400.0
) {
    for (i in 0 until count) {
        val angle = rotation + i * 0.2
        val radius = i * spacing
        val x = centerX + radius * cos(angle)
        val y = centerY + radius * sin(angle)
        point(x, y)
    }
}

program {
    var t = 0.0
    
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.strokeWeight = 2.0
        drawer.stroke = ColorRGBa.CYAN
        
        drawer.spiral(500, 0.5, t)  // ํšŒ์ „ํ•˜๋Š” ๋‚˜์„ 
        
        t += 0.02
    }
}

๊ณ ๊ธ‰: Drawer + Vector2 Extension

Vector2์— ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€

// Vector2์˜ ๊ฐ๋„์™€ ๊ฑฐ๋ฆฌ๋ฅผ ์–ป๊ธฐ
fun Vector2.angle(): Double {
    return atan2(y, x)
}

fun Vector2.magnitude(): Double {
    return sqrt(x * x + y * y)
}

// ์‚ฌ์šฉ
val v = Vector2(3.0, 4.0)
println(v.magnitude())  // 5.0
println(v.angle())      // ~0.93 ๋ผ๋””์•ˆ

Drawer์™€ Vector2 Extension ์กฐํ•ฉ

// Vector2 ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฒฝ๋กœ๋กœ ๊ทธ๋ฆฌ๊ธฐ
fun Drawer.path(points: List<Vector2>, closed: Boolean = false) {
    if (points.isEmpty()) return
    
    for (i in 0 until points.size - 1) {
        lineSegment(points[i], points[i + 1])
    }
    
    if (closed) {
        lineSegment(points.last(), points.first())
    }
}

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.stroke = ColorRGBa.WHITE
        
        val triangle = listOf(
            Vector2(400.0, 200.0),
            Vector2(600.0, 400.0),
            Vector2(200.0, 400.0)
        )
        
        drawer.path(triangle, closed = true)  // ์‚ผ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
    }
}

๊ธฐ๋ณธ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’ (Default Parameters)

Extension ํ•จ์ˆ˜์—์„œ ๊ธฐ๋ณธ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// ๋ฐ˜์ง€๋ฆ„์˜ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •
fun Drawer.grid(
    cols: Int,
    rows: Int,
    spacing: Double,
    radius: Double = 20.0  // ๊ธฐ๋ณธ๊ฐ’
) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, radius)
        }
    }
}

// ์‚ฌ์šฉ
extend {
    drawer.grid(10, 10, 80.0)          // radius = 20.0 (๊ธฐ๋ณธ๊ฐ’)
    drawer.grid(10, 10, 80.0, 30.0)    // radius = 30.0 (๋ช…์‹œ)
}

์ข‹์€ ๊ธฐ๋ณธ๊ฐ’ ์„ค๊ณ„:

  • ์ž์ฃผ ์“ฐ๋Š” ๊ฐ’์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ
  • ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฐ’๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ

์‹ค์ „ ์˜ˆ์ œ 4: ๋ณต์žกํ•œ ํŒจํ„ด

// ๋™์‹ฌ์›(concentric circles)
fun Drawer.concentricCircles(
    count: Int,
    startRadius: Double,
    spacing: Double,
    centerX: Double = 400.0,
    centerY: Double = 400.0
) {
    for (i in 0 until count) {
        val radius = startRadius + i * spacing
        circle(centerX, centerY, radius)
    }
}

// ๊ฒฉ์ž + ๋™์‹ฌ์› ์กฐํ•ฉ
program {
    var t = 0.0
    
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.WHITE
        
        // ๊ฒฉ์ž
        for (x in 0 until 5) {
            for (y in 0 until 5) {
                val cx = 100.0 + x * 160.0
                val cy = 100.0 + y * 160.0
                
                drawer.concentricCircles(
                    count = 3,
                    startRadius = 20.0,
                    spacing = 15.0,
                    centerX = cx,
                    centerY = cy
                )
            }
        }
        
        t += 0.01
    }
}

๋ฆฌ์‹œ๋ฒ„ ์ฒด์ด๋‹

Extension ํ•จ์ˆ˜๋Š” ๋‹ค๋ฅธ Extension ํ•จ์ˆ˜ ์•ˆ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// ๊ธฐ๋ณธ Extension
fun Drawer.box(
    x: Double,
    y: Double,
    width: Double,
    height: Double,
    cornerRadius: Double = 0.0
) {
    rectangle(x, y, width, height)
    // ๋ชจ์„œ๋ฆฌ ์ฒ˜๋ฆฌ ๋“ฑ...
}

// ๋‹ค๋ฅธ Extension์„ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด Extension
fun Drawer.tiled(
    cols: Int,
    rows: Int,
    width: Double,
    height: Double
) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            val px = x * width
            val py = y * height
            box(px, py, width, height)  // ๋‹ค๋ฅธ Extension ์‚ฌ์šฉ
        }
    }
}

extend {
    drawer.tiled(5, 5, 100.0, 100.0)
}

์œ ํ‹ธ๋ฆฌํ‹ฐ Extension ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งŒ๋“ค๊ธฐ

์ž์ฃผ ์“ฐ๋Š” Extension๋“ค์„ ํ•œ ํŒŒ์ผ์— ๋ชจ์•„์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// DrawerExtensions.kt (๋˜๋Š” ์•„๋ฌด ํŒŒ์ผ)

// ๊ฒฉ์ž
fun Drawer.grid(cols: Int, rows: Int, spacing: Double, radius: Double = 20.0) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, radius)
        }
    }
}

// ์›ํ˜• ๋ฐฐ์น˜
fun Drawer.radialLayout(
    count: Int,
    distance: Double,
    radius: Double = 20.0,
    centerX: Double = 400.0,
    centerY: Double = 400.0
) {
    require(count > 0)
    for (i in 0 until count) {
        val angle = TWO_PI * i / count
        val x = centerX + distance * cos(angle)
        val y = centerY + distance * sin(angle)
        circle(x, y, radius)
    }
}

// ๊ฒฝ๋กœ ๊ทธ๋ฆฌ๊ธฐ
fun Drawer.path(points: List<Vector2>, closed: Boolean = false) {
    if (points.isEmpty()) return
    for (i in 0 until points.size - 1) {
        lineSegment(points[i], points[i + 1])
    }
    if (closed) {
        lineSegment(points.last(), points.first())
    }
}

// ๋‚˜์„ 
fun Drawer.spiral(
    count: Int,
    spacing: Double,
    rotation: Double = 0.0,
    centerX: Double = 400.0,
    centerY: Double = 400.0
) {
    for (i in 0 until count) {
        val angle = rotation + i * 0.2
        val radius = i * spacing
        val x = centerX + radius * cos(angle)
        val y = centerY + radius * sin(angle)
        point(x, y)
    }
}

// --------- ๋ฉ”์ธ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉ ---------

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.WHITE
        
        // ๋ชจ๋“  Extension ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
        drawer.grid(10, 10, 80.0)
        drawer.radialLayout(8, 150.0)
        drawer.spiral(200, 1.0)
    }
}

Vector2 Extension์˜ ์‹ค์šฉ์„ฑ

๋ฒกํ„ฐ ์—ฐ์‚ฐ ํ™•์žฅ

// ์ •๊ทœํ™”๋œ ๋ฒกํ„ฐ (๋ฐฉํ–ฅ๋งŒ, ๊ฑฐ๋ฆฌ๋Š” 1)
fun Vector2.normalized(): Vector2 {
    val len = sqrt(x * x + y * y)
    if (len == 0.0) return Vector2(0.0, 0.0)
    return Vector2(x / len, y / len)
}

// ๋ฒกํ„ฐ์˜ ํšŒ์ „
fun Vector2.rotated(angleRadians: Double): Vector2 {
    val cos = cos(angleRadians)
    val sin = sin(angleRadians)
    return Vector2(
        x * cos - y * sin,
        x * sin + y * cos
    )
}

// ์‚ฌ์šฉ
val v = Vector2(1.0, 1.0)
val rotated = v.rotated(PI / 4)  // 45๋„ ํšŒ์ „
val norm = v.normalized()        // ์ •๊ทœํ™”

์‹ค์ œ ํ™œ์šฉ

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        
        val center = Vector2(400.0, 400.0)
        val direction = (mouse.position - center).normalized()
        
        // direction ๋ฐฉํ–ฅ์œผ๋กœ ์„  ๊ทธ๋ฆฌ๊ธฐ
        drawer.lineSegment(center, center + direction * 150.0)
    }
}

์‹ค์ „ ์˜ˆ์ œ: ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ๋‚˜์„ 

// ๋งˆ์šฐ์Šค๋ฅผ ๋”ฐ๋ผ๋‹ค๋‹ˆ๋Š” ๋‚˜์„ 
fun Drawer.spiralTowards(
    count: Int,
    spacing: Double,
    targetPosition: Vector2,
    rotation: Double = 0.0
) {
    for (i in 0 until count) {
        val angle = rotation + i * 0.2
        val radius = i * spacing
        
        val x = radius * cos(angle)
        val y = radius * sin(angle)
        
        val point = Vector2(x, y) + targetPosition
        circle(point.x, point.y, 2.0)
    }
}

program {
    var t = 0.0
    
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.CYAN
        
        spiralTowards(200, 0.8, mouse.position, t)
        
        t += 0.02
    }
}

์กฐ๊ฑด๋ถ€ ๋กœ์ง์ด ์žˆ๋Š” Extension

// ๊ฒฉ์ž + ์„ ํƒ์  ํ•„ํ„ฐ๋ง
fun Drawer.selectiveGrid(
    cols: Int,
    rows: Int,
    spacing: Double,
    radius: Double = 20.0,
    shouldDraw: (Int, Int) -> Boolean = { _, _ -> true }  // ๊ธฐ๋ณธ: ๋ชจ๋‘ ๊ทธ๋ฆฌ๊ธฐ
) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            if (shouldDraw(x, y)) {
                circle(x * spacing, y * spacing, radius)
            }
        }
    }
}

// ์‚ฌ์šฉ 1: ๊ธฐ๋ณธ (๋ชจ๋‘ ๊ทธ๋ฆฌ๊ธฐ)
extend {
    drawer.selectiveGrid(10, 10, 80.0)
}

// ์‚ฌ์šฉ 2: ์ฒด์ŠคํŒ ํŒจํ„ด
extend {
    drawer.selectiveGrid(10, 10, 80.0) { x, y ->
        (x + y) % 2 == 0
    }
}

// ์‚ฌ์šฉ 3: ๋Œ€๊ฐ์„  ํŒจํ„ด
extend {
    drawer.selectiveGrid(10, 10, 80.0) { x, y ->
        x == y
    }
}

๊ณ ๊ธ‰ ๊ธฐ๋Šฅ:

  • ๋งˆ์ง€๋ง‰ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋žŒ๋‹ค (์กฐ๊ฑด ํ•จ์ˆ˜)
  • ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ "๋ชจ๋‘ ๊ทธ๋ฆฌ๊ธฐ" ์ œ๊ณต
  • ํ˜ธ์ถœํ•  ๋•Œ ์กฐ๊ฑด์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

์ •๋ฆฌ: Extension ํ•จ์ˆ˜์˜ ์ด์ 

์ด์ ์„ค๋ช…
์žฌ์‚ฌ์šฉ์„ฑ๋ฐ˜๋ณต๋˜๋Š” ํŒจํ„ด์„ ํ•œ ๋ฒˆ๋งŒ ์ •์˜
๋ช…ํ™•์„ฑ์ฝ”๋“œ์˜ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•จ
๊ฐ€๋…์„ฑ๋ณต์žกํ•œ ๋กœ์ง์„ ๊ฐ„๋‹จํ•œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋กœ
์œ ์ง€๋ณด์ˆ˜ํŒจํ„ด ์ˆ˜์ • ์‹œ ํ•œ ๊ณณ๋งŒ ๋ณ€๊ฒฝ
์กฐํ•ฉ์ž‘์€ ๊ทธ๋ฆฌ๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ๋” ํฐ ํŒจํ„ด ๊ตฌ์„ฑ
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌํ™”์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋“ค์„ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌ

p5.js์™€์˜ ์ฐจ์ด

p5.js: ์ „์—ญ ํ•จ์ˆ˜

function drawGrid(cols, rows, spacing) {
    for (let x = 0; x < cols; x++) {
        for (let y = 0; y < rows; y++) {
            circle(x * spacing, y * spacing, 20);
        }
    }
}

function draw() {
    drawGrid(10, 10, 80);
}

๋ฌธ์ œ: ์ „์—ญ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์˜ค์—ผ, ์˜๋„ ๋ถˆ๋ช…ํ™•

OPENRNDR: Extension ํ•จ์ˆ˜

fun Drawer.grid(cols: Int, rows: Int, spacing: Double) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, 20.0)
        }
    }
}

extend {
    drawer.grid(10, 10, 80.0)
}

์žฅ์ : ๋ช…ํ™•ํ•œ ๊ด€๊ณ„, ์ฒด๊ณ„์  ์กฐ์ง, ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ์‚ฌ์šฉ


๋‹ค์Œ ๋‹จ๊ณ„: when ์กฐ๊ฑด ๋ถ„๊ธฐ

๋‹ค์Œ ๊ธ€์—์„œ๋Š” when ๋ฌธ๋ฒ•์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

if-else๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ•๋ ฅํ•œ ์กฐ๊ฑด ๋ถ„๊ธฐ:

val mode = 1  // ์•ž ๋‹จ๊ณ„์—์„œ ์„ ํƒํ•œ ๋ชจ๋“œ

when (mode) {
    0 -> drawer.grid(10, 10, 80.0)
    1 -> drawer.radialLayout(12, 150.0)
    2 -> drawer.spiral(200, 1.0)
    else -> drawer.clear(ColorRGBa.BLACK)
}

์ด๊ฒƒ์ด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํŒจํ„ด์„ ๊ทธ๋ฆฌ๋Š” ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์•„ํŠธ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.


์—ฐ์Šต ๋ฌธ์ œ

1. ๊ธฐ๋ณธ Extension ๋งŒ๋“ค๊ธฐ

// ์ •์ˆ˜์— "2๋ฐฐ๊ฐ€ ๋˜๋Š”๊ฐ€" ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
fun Int.isDouble(other: Int): Boolean {
    return this == other * 2
}

// ํ…Œ์ŠคํŠธ
println(10.isDouble(5))   // true
println(10.isDouble(3))   // false

2. Drawer Extension ๋งŒ๋“ค๊ธฐ

// ์ •์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ (์ค‘์‹ฌ ๊ธฐ์ค€)
fun Drawer.square(
    centerX: Double,
    centerY: Double,
    size: Double
) {
    val half = size / 2
    rectangle(centerX - half, centerY - half, size, size)
}

extend {
    drawer.square(400.0, 400.0, 100.0)
}

3. ๊ฒฉ์ž ๊ฐœ์„ 

radius๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ธฐ๋ณธ๊ฐ’์„ 20.0์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœํ•  ๋•Œ ์ƒ๋žตํ•˜๋ฉด ๋ฐ˜์ง€๋ฆ„ 20์˜ ์›, ๋„ค ๋ฒˆ์งธ ์ธ์ž๋ฅผ ์ฃผ๋ฉด ์ง€์ •ํ•œ ๋ฐ˜์ง€๋ฆ„์˜ ์›์ด ๊ทธ๋ ค์ง‘๋‹ˆ๋‹ค.

fun Drawer.grid(
    cols: Int,
    rows: Int,
    spacing: Double,
    radius: Double = 20.0
) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            circle(x * spacing, y * spacing, radius)
        }
    }
}

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.WHITE
        drawer.grid(12, 12, 60.0)       // ๊ธฐ๋ณธ ๋ฐ˜์ง€๋ฆ„ 20.0
        drawer.grid(12, 12, 60.0, 8.0)  // ๋ฐ˜์ง€๋ฆ„ 8.0
    }
}

๋‘ ๊ฒฉ์ž๋Š” ๊ฐ™์€ ๊ฐ„๊ฒฉ์œผ๋กœ ๊ทธ๋ ค์ง€๋ฉฐ, ๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ์€ ๋ฐ˜์ง€๋ฆ„์ด ๋” ์ž‘์Šต๋‹ˆ๋‹ค. ๋‘ ํ˜ธ์ถœ์„ ํ•จ๊ป˜ ๋‘๋ฉด ๋„ํ˜•์ด ๊ฒน์น˜๋ฏ€๋กœ ๋น„๊ตํ•  ๋•Œ๋Š” ํ•œ ๋ฒˆ์— ํ•œ ํ˜ธ์ถœ๋งŒ ๋‚จ๊ฒจ๋„ ๋ฉ๋‹ˆ๋‹ค.

4. ๋ณตํ•ฉ Extension

// Vector2 ๋ฆฌ์ŠคํŠธ๋ฅผ ์‹œ๊ฐํ™”
fun Drawer.visualizePoints(points: List<Vector2>, radius: Double = 5.0) {
    for (point in points) {
        circle(point.x, point.y, radius)
    }
}

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.PINK
        
        val points = (0 until 20)
            .map { Vector2(it * 40.0, 200.0 + 100.0 * sin(it.toDouble())) }
        
        drawer.visualizePoints(points, 10.0)
    }
}

5. ์‹ฌํ™”: ์กฐ๊ฑด๋ถ€ Grid

์กฐ๊ฑด ํ•จ์ˆ˜๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์œผ๋ฉด ๊ฒฉ์ž์—์„œ ๊ทธ๋ฆด ์…€์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ํ˜ธ์ถœ์€ ํ…Œ๋‘๋ฆฌ์™€ ์ฃผ๋Œ€๊ฐ์„ ์— ๋†“์ธ ์›๋งŒ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

fun Drawer.selectiveGrid(
    cols: Int,
    rows: Int,
    spacing: Double,
    shouldDraw: (Int, Int) -> Boolean
) {
    for (x in 0 until cols) {
        for (y in 0 until rows) {
            if (shouldDraw(x, y)) {
                circle(x * spacing, y * spacing, 12.0)
            }
        }
    }
}

program {
    extend {
        drawer.clear(ColorRGBa.BLACK)
        drawer.fill = ColorRGBa.CYAN
        val cols = 10
        val rows = 10
        drawer.selectiveGrid(cols, rows, 60.0) { x, y ->
            x == 0 || y == 0 || x == cols - 1 || y == rows - 1 || x == y
        }
    }
}

์กฐ๊ฑด์˜ ||๋Š” ์…€์˜ x ๋˜๋Š” y๊ฐ€ ๊ฐ€์žฅ์ž๋ฆฌ์ด๊ฑฐ๋‚˜, ๋‘ ์ธ๋ฑ์Šค๊ฐ€ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ฆ…๋‹ˆ๋‹ค. ํ…Œ๋‘๋ฆฌ์™€ ์™ผ์ชฝ ์œ„์—์„œ ์˜ค๋ฅธ์ชฝ ์•„๋ž˜๋กœ ์ด์–ด์ง€๋Š” ๋Œ€๊ฐ์„ ์ด ๋‚จ์Šต๋‹ˆ๋‹ค. ์ฒด์ŠคํŒ ๋ฌด๋Šฌ๋Š” ์กฐ๊ฑด์‹๋งŒ (x + y) % 2 == 0์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋ฉ๋‹ˆ๋‹ค.


profile
Coding Art with Blender / Three.js / p5.js / GLSL Shader / Processing / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€