๐ŸŒŸ p5.js์˜ map() ๊ณผ constrain() ๋ฉ”์„œ๋“œ

BamgasiJMยท2025๋…„ 12์›” 19์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
11/67
post-thumbnail

โ—† map()

map() ๋ฉ”์„œ๋“œ๋Š” ํ•œ ๋ฒ”์œ„(Range) ๋‚ด์˜ ๊ฐ’์„ ๋‹ค๋ฅธ ๋ฒ”์œ„ ๋‚ด์˜ ๊ฐ’์œผ๋กœ ์„ ํ˜•์ ์œผ๋กœ ๋ณ€ํ™˜(Scaling)ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
์ œ๋„ˆ๋ ˆ์ดํ‹ฐ๋ธŒ ์•„ํŠธ์—์„œ๋Š” ๋งˆ์šฐ์Šค ์œ„์น˜์™€ ๊ฐ™์€ ์ž…๋ ฅ ๊ฐ’์„ ์ƒ‰์ƒ ๊ฐ’์ด๋‚˜ ํฌ๊ธฐ ๊ฐ’ ๋“ฑ ์›ํ•˜๋Š” ์ถœ๋ ฅ ๋ฒ”์œ„๋กœ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•  ๋•Œ ํ•„์ˆ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

โ–ท ๋ฌธ๋ฒ•

map(value, start1, stop1, start2, stop2)
  • value : ๋ณ€ํ™˜ํ•˜๋ ค๋Š” ์ž…๋ ฅ ๊ฐ’ (์˜ˆ: ๋งˆ์šฐ์Šค ์œ„์น˜)
  • start1, stop1 : ์ž…๋ ฅ ๊ฐ’(value)์ด ์†ํ•œ ์›๋ž˜์˜ ๋ฒ”์œ„
  • start2, stop2 : ๋ณ€ํ™˜๋œ ๊ฐ’์„ ๋งตํ•‘ํ•  ๋ฒ”์œ„

โ–ท ๋™์ž‘ ์›๋ฆฌ

map() ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋‹ค์Œ ์ˆ˜ํ•™ ๊ณต์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ ํ˜• ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค

Output=(Inputโˆ’start1)ร—stop2โˆ’start2stop1โˆ’start1+start2\text{Output} = (\text{Input} - \text{start1}) \times \frac{\text{stop2} - \text{start2}}{\text{stop1} - \text{start1}} + \text{start2}

โ–ท ์˜ˆ์ œ ์ฝ”๋“œ

๋งˆ์šฐ์Šค์˜ X ์ขŒํ‘œ(0๋ถ€ํ„ฐ width๊นŒ์ง€)๋ฅผ ํšŒ์ƒ‰์กฐ ๋ฐฐ๊ฒฝ์ƒ‰(0๋ถ€ํ„ฐ 255๊นŒ์ง€)์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function setup() {
  createCanvas(400, 400);
  noStroke();
}

function draw() {
  // mouseX (0 ~ width) ๊ฐ’์„ grayscale (0 ~ 255) ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜
  let colorValue = map(mouseX, 0, width, 0, 255);

  // ๋ณ€ํ™˜๋œ ๊ฐ’์„ ๋ฐฐ๊ฒฝ์ƒ‰์œผ๋กœ ์„ค์ •
  background(colorValue);

  // (Optional) ํ™”๋ฉด ์ค‘์•™์— ์ •๋ณด ํ‘œ์‹œ
  fill(255 - colorValue); // ๋ฐฐ๊ฒฝ์ƒ‰๊ณผ ๋Œ€๋น„๋˜๋Š” ์ƒ‰์œผ๋กœ ์„ค์ •
  textSize(20);
  textAlign(CENTER, CENTER);
  text("Color: " + round(colorValue), width / 2, height / 2);
}

โ—† constrain()

constrain() ๋ฉ”์„œ๋“œ๋Š” ์–ด๋–ค ๊ฐ’์˜ ๋ฒ”์œ„๋ฅผ ํŠน์ • ์ตœ์†Œ๊ฐ’๊ณผ ์ตœ๋Œ€๊ฐ’ ์‚ฌ์ด๋กœ ์ œํ•œ(Clamping)ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
์ฆ‰, ๊ฐ’์ด ์ง€์ •๋œ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

โ–ท ๋ฌธ๋ฒ•

constrain(value, min, max)
  • value : ์ œํ•œํ•˜๋ ค๋Š” ์ž…๋ ฅ ๊ฐ’
  • min : ํ˜€์šฉ๋˜๋Š” ์ตœ์†Œ ๊ฐ’ (Minimum Value)
  • max : ํ—ˆ์šฉ๋˜๋Š” ์ตœ๋Œ€ ๊ฐ’ (Maximum Value)

โ–ท ๋™์ž‘ ์›๋ฆฌ

  • ๋งŒ์•ฝ value๊ฐ€ min๋ณด๋‹ค ์ž‘์œผ๋ฉด (value < min), min์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ value๊ฐ€ max๋ณด๋‹ค ํฌ๋ฉด (value > max), max๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ value๊ฐ€ min๊ณผ max ์‚ฌ์ด์— ์žˆ์œผ๋ฉด, value ๊ทธ ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

โ–ท ์˜ˆ์ œ ์ฝ”๋“œ

map() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ„์‚ฐ๋œ ๊ฐ’์ด ์˜๋„์น˜ ์•Š๊ฒŒ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚  ๊ฒฝ์šฐ, ์ด ๊ฐ’์„ ํŠน์ • ๋ฒ”์œ„๋กœ ์ œํ•œํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);

  // ๋งˆ์šฐ์Šค ์œ„์น˜์— ๋”ฐ๋ผ ์›์˜ ํฌ๊ธฐ๋ฅผ (0~100)์œผ๋กœ ๋ณ€ํ™˜
  let mappedSize = map(mouseX, 0, width, 0, 100);

  // mappedSize์— 150์„ ๋”ํ•œ ๊ฐ’์„ ์ƒˆ๋กœ์šด ํฌ๊ธฐ ํ›„๋ณด๋กœ ์‚ฌ์šฉ (250๊นŒ์ง€ ์ปค์งˆ ์ˆ˜ ์žˆ์Œ)
  let newSize = mappedSize + 150;

  // constrain()์„ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ข… ํฌ๊ธฐ๋ฅผ 100๊ณผ 200 ์‚ฌ์ด๋กœ ์ œํ•œ
  // ์•„๋ฌด๋ฆฌ ๋งˆ์šฐ์Šค๋ฅผ ์›€์ง์—ฌ๋„ ์›์˜ ํฌ๊ธฐ๋Š” 100๋ณด๋‹ค ์ž‘์–ด์ง€๊ฑฐ๋‚˜ 200๋ณด๋‹ค ์ปค์ง€์ง€ ์•Š์Œ
  let finalSize = constrain(newSize, 100, 200);

  fill(30, 190, 170);
  ellipse(width / 2, height / 2, finalSize, finalSize);

  // (Optional) ํ™”๋ฉด ์ค‘์•™์— ํฌ๊ธฐ ์ •๋ณด ํ‘œ์‹œ
  fill(0);
  textSize(13);
  textAlign(CENTER, CENTER);
  text("Final Size: " + round(finalSize), width / 2, height / 2);
}

โ—† ์ข…ํ•ฉ ์˜ˆ์‹œ

// ๋„ํ˜•์˜ ์ตœ์†Œ/์ตœ๋Œ€ ํฌ๊ธฐ ์„ค์ •
const MIN_SIZE = 300;
const MAX_SIZE = 700;

// ๋‹ค๊ฐํ˜•์˜ ์ตœ์†Œ/์ตœ๋Œ€ ์ •์  ์ˆ˜ ์„ค์ • (3~128 ์‚ฌ์ด)
const MIN_VERTICES = 3;
const MAX_VERTICES = 128;

function setup() {
  createCanvas(800, 800);
  angleMode(DEGREES); // ๊ฐ๋„ ๋‹จ์œ„๋ฅผ Degree(๋„)๋กœ ์„ค์ •
  noStroke();
}

function draw() {
  background(25); // ์–ด๋‘์šด ๋ฐฐ๊ฒฝ

  // 1. ํ™”๋ฉด ์ค‘์•™์„ ๊ธฐ์ค€์œผ๋กœ ๋งˆ์šฐ์Šค ์œ„์น˜ ๊ณ„์‚ฐ
  // centerDeltaX: ๋งˆ์šฐ์Šค X์ขŒํ‘œ์™€ ์ค‘์‹ฌ X์ขŒํ‘œ ๊ฐ„์˜ ์ฐจ์ด (-width/2 ~ +width/2)
  let centerDeltaX = mouseX - width / 2;
  // centerDeltaY: ๋งˆ์šฐ์Šค Y์ขŒํ‘œ์™€ ์ค‘์‹ฌ Y์ขŒํ‘œ ๊ฐ„์˜ ์ฐจ์ด (-height/2 ~ +height/2)
  let centerDeltaY = mouseY - height / 2;

  // --- ๋งคํ•‘ ๋ฐ ์ œํ•œ ---

  // 2. X์ถ• ์œ„์น˜๋ฅผ '์ƒ‰์ƒ ๊ฐ’ (Hue)'์œผ๋กœ ๋งคํ•‘ ๋ฐ ์ œํ•œ
  // centerDeltaX ๋ฒ”์œ„: -width/2 ~ width/2
  // ๋ชฉํ‘œ ์ƒ‰์ƒ ๋ฒ”์œ„ (HUE): 0 ~ 360 (์ƒ‰์ƒํ™˜ ์ „์ฒด)
  let mappedHue = map(centerDeltaX, -width / 2, width / 2, 0, 360);

  // map() ํ•จ์ˆ˜๋Š” stop1, stop2๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฐ’๋„ ๋น„๋ก€์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ,
  // ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด constrain์œผ๋กœ ๋ฒ”์œ„๋ฅผ ๋ช…ํ™•ํžˆ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. (์˜ต์…˜)
  let finalHue = constrain(mappedHue, 0, 360);

  // 3. Y์ถ• ์œ„์น˜๋ฅผ 'ํฌ๊ธฐ'๋กœ ๋งคํ•‘ ๋ฐ ์ œํ•œ
  // centerDeltaY ๋ฒ”์œ„: -height/2 ~ height/2
  // ๋ชฉํ‘œ ํฌ๊ธฐ ๋ฒ”์œ„: MIN_SIZE ~ MAX_SIZE
  let mappedSize = map(
    centerDeltaY,
    -height / 2,
    height / 2,
    MIN_SIZE,
    MAX_SIZE
  );
  let finalSize = constrain(mappedSize, MIN_SIZE, MAX_SIZE);

  // 4. ๋งˆ์šฐ์Šค์™€ ์ค‘์•™ ์‚ฌ์ด์˜ '๊ฑฐ๋ฆฌ'๋ฅผ '์ •์  ์ˆ˜'๋กœ ๋งคํ•‘ ๋ฐ ์ œํ•œ
  // dist() ํ•จ์ˆ˜๋กœ ๋งˆ์šฐ์Šค์™€ ์ค‘์•™(width/2, height/2) ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ (0 ~ max_diagonal)
  let distFromCenter = dist(mouseX, mouseY, width / 2, height / 2);
  let maxDist = dist(0, 0, width / 2, height / 2); // ์ตœ๋Œ€ ๊ฑฐ๋ฆฌ (์ฝ”๋„ˆ๊นŒ์ง€)

  // ๊ฑฐ๋ฆฌ ๋ฒ”์œ„: 0 ~ maxDist
  // ๋ชฉํ‘œ ์ •์  ์ˆ˜ ๋ฒ”์œ„: MIN_VERTICES ~ MAX_VERTICES
  let mappedVertices = map(
    distFromCenter,
    0,
    maxDist,
    MIN_VERTICES,
    MAX_VERTICES
  );

  // ์ •์  ์ˆ˜๋Š” ์ •์ˆ˜์—ฌ์•ผ ํ•˜๋ฏ€๋กœ, mappedVertices๋ฅผ ์ •์ˆ˜ํ™” (round, floor, ceil ์ค‘ ํƒ 1)
  let rawVertices = round(mappedVertices);

  // ๋‹ค๊ฐํ˜• ์ •์  ์ˆ˜๋ฅผ 3~128 ์‚ฌ์ด๋กœ ์ตœ์ข… ์ œํ•œ
  let finalVertices = constrain(rawVertices, MIN_VERTICES, MAX_VERTICES);

  // --- ๋„ํ˜• ๊ทธ๋ฆฌ๊ธฐ ---

  // HSB(Hue, Saturation, Brightness) ์ปฌ๋Ÿฌ ๋ชจ๋“œ ์„ค์ •
  colorMode(HSB, 360, 100, 100);
  fill(finalHue, 100, 100); // ๋งคํ•‘๋œ HUE ๊ฐ’์œผ๋กœ ์ฑ„์šฐ๊ธฐ

  // ๋„ํ˜•์„ ํ™”๋ฉด ์ค‘์•™์— ์œ„์น˜์‹œํ‚ต๋‹ˆ๋‹ค.
  push();
  translate(width / 2, height / 2);

  // ๋‹ค๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ
  drawPolygon(0, 0, finalSize / 2, finalVertices); // finalSize๋ฅผ ์ง€๋ฆ„์œผ๋กœ ์‚ฌ์šฉ

  pop();

  // --- ์ •๋ณด ํ‘œ์‹œ ---
  colorMode(RGB); // ๋‹ค์‹œ ๊ธฐ๋ณธ RGB ๋ชจ๋“œ๋กœ ์ „ํ™˜
  fill(255);
  textAlign(CENTER, TOP);
  textSize(20);
  text(`Hue (X): ${round(finalHue)}`, width / 2, height /2 - 20);
  text(`Size (Y): ${round(finalSize)}`, width / 2, height / 2 );
  text(`Vertices (Dist): ${finalVertices}`, width / 2, height / 2 + 20);
}

/**
 * ์ง€์ •๋œ ์œ„์น˜์— ์ •๋‹ค๊ฐํ˜•์„ ๊ทธ๋ฆฌ๋Š” ํ•จ์ˆ˜
 * @param x x ์ขŒํ‘œ
 * @param y y ์ขŒํ‘œ
 * @param radius ๋ฐ˜์ง€๋ฆ„
 * @param npoints ์ •์  ์ˆ˜
 */
function drawPolygon(x, y, radius, npoints) {
  let angle = 360 / npoints; // ๊ฐ ์ •์  ์‚ฌ์ด์˜ ๊ฐ๋„
  beginShape();
  for (let a = 0; a < 360; a += angle) {
    let sx = x + cos(a) * radius;
    let sy = y + sin(a) * radius;
    vertex(sx, sy);
  }
  endShape(CLOSE);
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

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