Skip to content
thingsub edited this page Dec 26, 2025 · 20 revisions

Plotto Spine Code

0. ๊ฐœ์š”

๋ณธ ๋ฌธ์„œ๋Š” ๋กœ๋ด‡ ๋“œ๋กœ์ž‰ ์‹œ์Šคํ…œ Plotto์˜ Spine.js ํŒŒ์ผ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ๋Š” Plotto ๋กœ๋ด‡ ํŒ” ์ฝ”๋“œ์˜ ๊ตฌ์„ฑ ์š”์†Œ์™€ ์ž‘๋™ ๋ฐฉ์‹์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ๋Š” 2์ž์œ ๋„(2-DOF) ๋กœ๋ด‡ ํŒ”์„ ์ œ์–ดํ•˜์—ฌ SVG๋กœ ์ •์˜๋œ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ํŽœ์œผ๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฌ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ์˜ ์ฃผ์š” ์ƒ์ˆ˜, ํด๋ž˜์Šค ์†์„ฑ, ํ•จ์ˆ˜, ๊ทธ๋ฆฌ๊ณ  ์ „์ฒด์ ์ธ ๋™์ž‘ ํ๋ฆ„์„ ๋‹จ๊ณ„์ ์œผ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


1. ์ƒ์ˆ˜ ์ •์˜

์ž์„ธํžˆ ๋ณด๊ธฐ

์ฝ”๋“œ ์ƒ๋‹จ์—๋Š” ๋กœ๋ด‡ ํŒ”์˜ ๋ฌผ๋ฆฌ์ ์ธ ์น˜์ˆ˜์™€ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ƒ์ˆ˜๋“ค์ด ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์„ค๋ช…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • TOP_JOINT

    ๋กœ๋ด‡ ํŒ” ์ƒ๋ถ€ ๊ด€์ ˆ์˜ ์ด๋ฏธ์ง€ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค.

    const TOP_JOINT_X = 220;
    const TOP_JOINT_Y = 547;
  • UPPER_JOINT_BASE

    ๋กœ๋ด‡ ํŒ” ์ƒ๋ถ€ ์•”(upper arm)์ด ๊ธฐ์ค€(base)์— ๋ถ€์ฐฉ๋œ ์ง€์ ์˜ ์ด๋ฏธ์ง€ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค. ์ƒ๋ถ€ ์•”์˜ ์‹œ์ž‘์ ์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    const UPPER_JOINT_BASE_X = 747;
    const UPPER_JOINT_BASE_Y = 226;
  • UPPER_JOINT_ELBOW

    : ์ „์™„์˜ ์‹œ์ž‘์ (ํŒ”๊ฟˆ์น˜)์˜ ์ด๋ฏธ์ง€ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” UPPER_JOINT_ELBOW์™€ ๋™์ผํ•œ ์œ„์น˜์—ฌ์•ผ ํ•˜์ง€๋งŒ, ์ธก์ • ์˜ค์ฐจ๋กœ ์•ฝ๊ฐ„ ์ฐจ์ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    const UPPER_JOINT_ELBOW_X = 195;
    const UPPER_JOINT_ELBOW_Y = 383;
  • FORE_JOINT_ELBOW

    ์ „์™„์˜ ์‹œ์ž‘์ (ํŒ”๊ฟˆ์น˜)์˜ ์ด๋ฏธ์ง€ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” UPPER_JOINT_ELBOW์™€ ๋™์ผํ•œ ์œ„์น˜์—ฌ์•ผ ํ•˜์ง€๋งŒ, ์ธก์ • ์˜ค์ฐจ๋กœ ์•ฝ๊ฐ„ ์ฐจ์ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    const FORE_JOINT_ELBOW_X = 195;
    const FORE_JOINT_ELBOW_Y = 385;
  • FORE_PEN

    ๋กœ๋ด‡ ํŒ” ๋์— ๋ถ€์ฐฉ๋œ ํŽœ(Pen) ๋์ ์˜ ์ด๋ฏธ์ง€ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค. ์ „์™„์˜ ๋์ (ํŽœ์ด ์œ„์น˜ํ•œ ์ง€์ )์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

    const FORE_PEN_X = 778;
    const FORE_PEN_Y = 612;
  • imageScale

    ์ด๋ฏธ์ง€ ์ขŒํ‘œ๋ฅผ ์‹ค์ œ ๋กœ๋ด‡์˜ ๊ธธ์ด ๋‹จ์œ„๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ์Šค์ผ€์ผ ๊ณ„์ˆ˜์ž…๋‹ˆ๋‹ค.

    ์˜ˆ) const imageScale = 0.5; : ์ด๋ฏธ์ง€ ๊ธธ์ด๋ฅผ ์ ˆ๋ฐ˜ ์Šค์ผ€์ผ ํ›„ ์‹ค์ œ ๊ธธ์ด๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฐ’๋“ค์€ ๋กœ๋ด‡ ํŒ”์˜ ๊ธฐ๊ตฌํ•™์  ํŠน์„ฑ์„ ์„ค์ •ํ•˜๊ณ , ์ด๋ฏธ์ง€ ๋˜๋Š” ์„ค๊ณ„๋„์—์„œ ์ธก์ •๋œ ์ขŒํ‘œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๋ด‡ ํŒ”์˜ ๊ธธ์ด์™€ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ ์ฃผ์š” Plotto์˜ ํด๋ž˜์Šค๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


2. ํด๋ž˜์Šค ์ •์˜

ํ•„๋“œ(๋ณ€์ˆ˜)

๋ชจ๋“  ๋ณ€์ˆ˜๋Š” getter / setter๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

#baseX, #baseY

๋กœ๋ด‡ํŒ” ๊ธฐ์ค€ ์ขŒํ‘œ์ž…๋‹ˆ๋‹ค. joint1์˜ ๋ชจํ„ฐ ๋ถ€๋ถ„์ด ์œ„์น˜ํ•˜๋Š” ์ขŒํ‘œ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

#link1, #link2

๋กœ๋ด‡ ํŒ”์˜ ๋‘ ๊ด€์ ˆ ์‚ฌ์ด ๊ธธ์ด๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. #link1์€ ์ƒ๋ถ€ ํŒ”(joint1 ~ joint2)์˜ ๊ธธ์ด, #link2๋Š” ํ•˜๋ถ€ ํŒ”(joint2 ~ pen)์˜ ๊ธธ์ด์ž…๋‹ˆ๋‹ค. ์ด ๊ฐ’๋“ค์€ initLinkGeometry()ํ•จ์ˆ˜์—์„œ ๊ณ„์‚ฐ๋ฉ๋‹ˆ๋‹ค.

#upperRestAngle, #foreRestAngle

๋กœ๋ด‡ํŒ”์ด ๊ธฐ์ค€ ์ž์„ธ์‹œ ์ด๋ฏธ์ง€ ๊ฐ๋„๋ฅผ ๋ผ๋””์•ˆ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐ’ ์ž…๋‹ˆ๋‹ค. upperRestAngle์€ ์ƒ๋ถ€ ํŒ”์˜ ์ด๋ฏธ์ง€ ๊ฐ๋„ ์ž…๋‹ˆ๋‹ค, foreRestAngle์€ ํ•˜๋ถ€ ํŒ”์˜ ์ด๋ฏธ์ง€ ๊ฐ๋„ ์ž…๋‹ˆ๋‹ค. ์ด ๋‘ ๊ฐ๋„๋Š” ์ˆœ / ์—ญ ๊ธฐ๊ตฌํ•™ ๊ณ„์‚ฐ์— ๋ณด์ •๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

#JOINT2_OFFSET

๋‘๋ฒˆ์งธ ๊ด€์ ˆ์˜ ์˜คํ”„์…‹ ๊ฐ๋„(offset)์ž…๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ ๋กœ๋ด‡์˜ ๊ฐ๋„ ๊ธฐ์ค€๊ณผ ๋งž์ถ”๊ธฐ ์œ„ํ•œ offset์œผ๋กœ, ๋กœ๋ด‡ํŒ”์ด ใ„ท์ž ๋ชจ์–‘์ผ ๋•Œ, joint2๊ฐ€ 0๋„์ด๊ธฐ๋ฅผ ๋ณด์žฅํ•˜๋Š” offset ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๋ด‡ joint2 ์—”์ฝ”๋”๊ฐ€ 0์ผ๋•Œ, ์‹ค์ œ ๋กœ๋ด‡ํŒ”์ด 143๋„๋ฅผ ์ด๋ฃจ๊ณ  ์žˆ๋‹ค๋ฉด JOINT2_OFFSET = 143์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ๊ธฐ๊ตฌํ•™ ๊ณ„์‚ฐ์‹œ ๋ณด์ •ํ•ฉ๋‹ˆ๋‹ค.

#minEncoderJoint1, #maxEncoderJoint1, #minEncoderJoint2, #maxEncoderJoint2

๋กœ๋ด‡ํŒ” ๊ด€์ ˆ์˜ ๊ฐ๋„ ํ•œ๊ณ„(์ œ์•ฝ)์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋กœ๋ด‡ํŒ”์˜ ๋ฌผ๋ฆฌ์  ์ œํ•œ์ด๋‚˜ ์•ˆ์ „ ๋ฒ”์œ„๋ฅผ ์„ค์ •ํ•œ ๊ฐ’์œผ๋กœ, ๊ฐ ๊ด€์ ˆ์ด ์›€์ง์ผ ์ˆ˜ ์žˆ๋Š” ์ตœ์†Œ/์ตœ๋Œ€ ๊ฐ๋„๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

#STEP_DEG

์—”์ฝ”๋” ์Šคํ…๋‹น ๊ฐ๋„๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ฆ‰, ๊ด€์ ˆ์„ ํ•œ ์Šคํ… ์›€์ง์˜€์„ ๋•Œ ๋ช‡ ๋„๊ฐ€ ํšŒ์ „๋˜๋Š”์ง€ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ •์˜ ๊ฐ’ 0.0109...๋Š” 11.25 % 16 % 64๋กœ ๊ณ„์‚ฐ๋œ ๊ฐ’์ž…๋‹ˆ๋‹ค.

#MAX_STEPS_PT

ํ•œ ๋ช…๋ น์— ํ—ˆ์šฉ๋˜๋Š” ์ตœ๋Œ€ ์Šคํ…์ˆ˜ ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  motionJson์—์„œ์˜ ๋ช…๋ น์€ MAX_STEPS_PT๋ฅผ ๋„˜์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

#MAX_DELTA_DEG

๋‘ ์  ์‚ฌ์ด ์ตœ๋Œ€ ํ—ˆ์šฉ ๊ฐ๋„ ๋ณ€ํ™”๋Ÿ‰ ์ž…๋‹ˆ๋‹ค. #STEP_DEG * #MAX_STEPS_PT๋ฅผ ๊ณฑํ•˜์—ฌ ๊ณ„์‚ฐ๋˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ 0.07๋„ ์ •๋„๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

#SVG_BOX_SIZE

SVG ๊ฒฝ๋กœ๋ฅผ ๋กœ๋ด‡ ์ขŒํ‘œ์— ๋งคํ•‘ํ•  ๋•Œ์˜ ์ •๊ทœํ™” ๋ฐ•์Šค ํฌ๊ธฐ ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ 250์œผ๋กœ ๋งคํ•‘๋˜์–ด ์žˆ์œผ๋ฉฐ, ๋กœ๋ด‡ํŒ”์ด (0,0) ~ (250,250) ๋ฐ•์Šค ์•ˆ์— ์žˆ๋Š” ์ •๋ณด๋Š” ๊ทธ๋ฆด ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋กœ๋ด‡์ด ๊ทธ๋ฆด ๊ทธ๋ฆผ์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ ์ •์˜ํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

#svgPathPoints

svg๊ฒฝ๋กœ๋กœ๋ถ€ํ„ฐ ์ถ”์ถœํ•œ ์  ์ขŒํ‘œ ๋ฆฌ์ŠคํŠธ ์ž…๋‹ˆ๋‹ค. ์ด ๋ฆฌ์ŠคํŠธ์—๋Š” {x,y,pen}์˜ ํ˜•ํƒœ๋กœ ๊ฐ์ฒด๋“ค์ด ์ˆœ์„œ๋Œ€๋กœ ๋“ค์–ด ์žˆ์œผ๋ฉฐ, ์ด ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด motionJson ์ƒ์„ฑ์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

#motionJson

๋กœ๋ด‡ ํŒ”์ด ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์›€์ง์ด๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์„ธ๋ถ€ ๋ช…๋ น ๋ชฉ๋ก ์ž…๋‹ˆ๋‹ค. ๊ฐ ๋ช…๋ น์€{d1,d2,pen}์˜ ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๋ฉฐ, d1, d2๋Š” ๋‹ค์Œ ๋ชฉ์ ์ง€๋กœ ๊ฐ€๊ธฐ ์œ„ํ•ด ์›€์ง์—ฌ์•ผ ํ•  step ์ •์ˆ˜ ๊ฐ’์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋˜ํ•œ pen์€ ํ•ด๋‹น ์ง€์ ์—์„œ์˜ pen์˜ ์ƒํƒœ(0 = ๋“ค์–ด์˜ฌ๋ฆผ, 1 = ๋‚ด๋ ค๋†“์Œ)์ž…๋‹ˆ๋‹ค. motionJson์€ buildMotionJsonFromSvg()์—์„œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

#plot

motionJson์œผ๋กœ ์ƒ์„ฑ๋œ 1๋ฐ”์ดํŠธ ๋ฐฐ์—ด๋กœ, d1,d2,pen์˜ ๊ฐ’์— ๋”ฐ๋ผ 1๋ฐ”์ดํŠธ๋กœ ์••์ถ•ํ•˜์—ฌ ํ‘œํ˜„ํ•œ ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค. plot์˜ ํ‘œํ˜„ ๋ฐฉ์‹์— ๋Œ€ํ•ด์„  [Plotto_Path]๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”

#jsonBuilt

boolean ๊ฐ’์œผ๋กœ, ํ˜„ svg์— ๋Œ€ํ•ด motionJson์ด ์ƒ์„ฑ๋œ ์ ์ด ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. svg๊ฒฝ๋กœ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ motionJson๋ฅผ ๋งŒ๋“ค๋ฉด, true๋กœ ์„ค์ •๋˜๋ฉฐ, configure()๋“ฑ์œผ๋กœ ์„ค์ •์ด ๋ณ€๊ฒฝ๋˜๋ฉด false๋กœ ๋ฆฌ์…‹๋ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€์ˆ˜๋Š” ๋™์ผํ•œ ๊ฒฝ๋กœ์— ๋Œ€ํ•ด motionJson ์ค‘๋ณต ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•˜๋Š”๋ฐ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

constructor()

new Plotto()๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ํ˜ธ์ถœ๋˜๋Š” ์ƒ์„ฑ์ž์ž…๋‹ˆ๋‹ค. $("encoder.joint_1").d = 0, $("encoder.joint_2").d = 0์™€ ๊ฐ™์€ ์—”์ฝ”๋” ๊ฐ’ ์ดˆ๊ธฐํ™”, $('pen').d = 0๋กœ ์ดˆ๊ธฐ๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ํ•„๋“œ์— ์žˆ๋Š” ๋ณ€์ˆ˜๋“ค์„ ํ•œ๋ฒˆ์— ๋ณ€๊ฒฝ ์‹œ์—” configure() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

configure()

ํ•„๋“œ์— ์žˆ๋Š” ๋ชจ๋“  ๋ณ€์ˆ˜๋ฅผ ํ•œ๋ฒˆ์— ํšจ์œจ์ ์œผ๋กœ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์—ฌ๋Ÿฌ ์˜ต์…˜์„ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋ฐ›์œผ๋ฉฐ, ๊ฐ ์˜ต์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

option
ํ•ญ๋ชฉ ์„ค๋ช… ๊ธฐ๋ณธ๊ฐ’ / ๋น„๊ณ 
baseX, baseY ๋กœ๋ด‡ ํŒ” ๋ฒ ์ด์Šค(Joint 1)์˜ ๊ธฐ์ค€ ์ขŒํ‘œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. (0, 0)
link1Length ์ƒ๋ถ€ ์•”(link1)์˜ ๊ธธ์ด๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ์ง€์ • ์‹œ initLinkGeometry()์—์„œ ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ ์ž๋™ ๊ณ„์‚ฐ
link2Length ์ „์™„(link2)์˜ ๊ธธ์ด๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ์ง€์ • ์‹œ initLinkGeometry()์—์„œ ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ ์ž๋™ ๊ณ„์‚ฐ
upperRestAngle ์ƒ๋ถ€ ์•”์˜ ๊ธฐ์ค€ ์ž์„ธ ๊ฐ๋„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. (๋ผ๋””์•ˆ) ๋ฏธ์ง€์ • ์‹œ ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ ์ž๋™ ๊ณ„์‚ฐ
foreRestAngle ์ „์™„์˜ ๊ธฐ์ค€ ์ž์„ธ ๊ฐ๋„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. (๋ผ๋””์•ˆ) ๋ฏธ์ง€์ • ์‹œ ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ ์ž๋™ ๊ณ„์‚ฐ
JOINT2_OFFSET ํŒ”๊ฟˆ์น˜(Joint 2) ๊ด€์ ˆ์˜ ๊ธฐ๊ณ„์  ์˜คํ”„์…‹ ๊ฐ๋„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. 143ยฐ
SVG_BOX_SIZE SVG ๊ฒฝ๋กœ ์ •๊ทœํ™”์— ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ค€ ๋ฐ•์Šค ํฌ๊ธฐ์ž…๋‹ˆ๋‹ค. 250
STEP_DEG ์—”์ฝ”๋” 1์Šคํ…๋‹น ํšŒ์ „ ๊ฐ๋„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‹œ MAX_DELTA_DEG ์ž๋™ ์žฌ๊ณ„์‚ฐ
MAX_STEPS_PT ํฌ์ธํŠธ ๊ฐ„ ํ—ˆ์šฉ๋˜๋Š” ์ตœ๋Œ€ ์—”์ฝ”๋” ์Šคํ… ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‹œ MAX_DELTA_DEG ์ž๋™ ์žฌ๊ณ„์‚ฐ
minJoint1 Joint 1(์ƒ๋ถ€ ์•”)์˜ ์ตœ์†Œ ๊ฐ๋„ ์ œํ•œ ์‚ฌ์šฉ์ž ์„ค์ •
maxJoint1 Joint 1(์ƒ๋ถ€ ์•”)์˜ ์ตœ๋Œ€ ๊ฐ๋„ ์ œํ•œ ์‚ฌ์šฉ์ž ์„ค์ •
minJoint2 Joint 2(์ „์™„)์˜ ์ตœ์†Œ ๊ฐ๋„ ์ œํ•œ ์‚ฌ์šฉ์ž ์„ค์ •
maxJoint2 Joint 2(์ „์™„)์˜ ์ตœ๋Œ€ ๊ฐ๋„ ์ œํ•œ ์‚ฌ์šฉ์ž ์„ค์ •
๋‚ด๋ถ€ ๋™์ž‘ ์ˆœ์„œ

๊ธฐ๊ตฌํ•™์  ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ • : ์ธ์ž์— ๋”ฐ๋ผ #baseX, #baseY, #link1, #link2,upperRestAngle, foreRestAngle, JOINT2_OFFSET ๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ „๋‹ฌ๋˜์ง€ ์•Š์€ ๊ฐ’์€ ์ด์ „ ์„ค์ •์ด๋‚˜ ๊ธฐ๋ณธ๊ฐ’์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. SVG / ์–‘์žํ™” ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ • : SVG_BOX_SIZE, STEP_DEG, MAX_STEPS_PT ๊ฐ’์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ STEP_DEG๋‚˜ MAX_STEPS_PT๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ #MAX_DELTA_DEG (์ตœ๋Œ€ ๊ฐ๋„ ๋ณ€ํ™”๋Ÿ‰)๋„ ์ƒˆ๋กœ์šด ๊ฐ’์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค. ๊ด€์ ˆ ์ œํ•œ ์„ค์ • : ๋งŒ์•ฝ ์ƒˆ๋กœ์šด ๊ด€์ ˆ ๊ฐ๋„ ์ œํ•œ ๊ฐ’๋“ค์ด ์ฃผ์–ด์ง€๋ฉด ํ•ด๋‹น ๊ฐ’์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „ ๊ฒฝ๋กœ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” : ์„ค์ •์ด ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฏ€๋กœ, #jsonBuilt๋ฅผ false๋กœ ํ•˜๊ณ , #motionJson๊ณผ #plot ๋ฐฐ์—ด์„ ๋นˆ ๋ฐฐ์—ด๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, initLinkGeometry()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, ํ˜„์žฌ ์ด๋ฏธ์ง€ ์ •๋ณด ์ƒ #link1, #link2, #upperRestAngle, #foreRestAngle์„ ๊ณ„์‚ฐํ•˜์—ฌ ํ•„๋“œ์— ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

fkPenXY_deg(j1Deg, j2Deg)

์ด ํ•จ์ˆ˜๋Š” ๊ด€์ ˆ ๊ฐ๋„(j1Deg, j2Deg)๋ฅผ ๋ฐ›์•„ ํŽœ ๋ ์ขŒํ‘œ(x3,y3)๋ฅผ ๊ณ„์‚ฐํ•ด ์ค๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

๊ฐ๋„ ๋ณ€ํ™˜ : ์šฐ์„  ๋„ ๋‹จ์œ„์ธ j1Deg๋ฅผ ๋ผ๋””์•ˆ์— ๋งž๊ฒŒ ๋ณ€ํ™˜ํ•˜๋ฉฐ, ๋ถ€ํ˜ธ๋ฅผ ๋’ค์ง‘์Šต๋‹ˆ๋‹ค(๋กœ๋ด‡ ์ขŒํ‘œ๊ฒŒ(์‹œ๊ณ„ -, ๋ฐ˜์‹œ๊ณ„ +)์™€ ๋ฐ˜๋Œ€์ด๊ธฐ ๋•Œ๋ฌธ). ์ด ๋ณ€ํ™˜ํ•œ ์ˆ˜๋ฅผ theta1์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

์ดํ›„ theta1์— upperRestAngle์„ ๋”ํ•œ ๊ฐ๋„๋ฅผ theta1_ft์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ด๋ฏธ์ง€ ์ƒ์˜ ๋กœ๋ด‡ํŒ” ๊ฐ๋„๋ฅผ ๋”ํ•œ ์‹ค์ œ ๊ด€์ ˆ ๊ฐ๋„์ž…๋‹ˆ๋‹ค.

j2Deg + this.JOINT2_OFFSET์„ ๋”ํ•œ ์‹ค์ œ ๊ฐ๋„ ๊ฐ’์„ ๋ผ๋””์•ˆ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋ถ€ํ˜ธ๋ฅผ ๋’ค์ง‘์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ theta2์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ํŒ”๊ฟˆ์น˜ ์ขŒํ‘œ(x2,y2) ๊ณ„์‚ฐ :
๋‹ค์Œ์œผ๋กœ ์ขŒํ‘œ ๊ณ„์‚ฐ์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ •๊ธฐ๊ตฌํ•™ ๊ณต์‹๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

x2 = baseX + link1 * cos(theta1_fk);
y2 = baseY + link1 * sin(theta1_fk);

(baseX, baseY)๋Š” ๋กœ๋ด‡ joint1 ๋ชจํ„ฐ์˜ ์œ„์น˜, link1์€ ์ƒ๋ถ€ ์•” ๊ธธ์ด์ž…๋‹ˆ๋‹ค.

ํŽœ ๋ ์ขŒํ‘œ(x3,y3) ๊ณ„์‚ฐ :

x3 = x2 + link2 * cos(theta1_fk + theta2);
y3 = y2 + link2 * sin(theta1_fk + theta2);

ํŒ”๊ฟˆ์น˜์—์„œ๋ถ€ํ„ฐ theta2๋งŒํผ ๋” ํšŒ์ „ํ•˜๋ฏ€๋กœ, ํŒ”๊ฟˆ์น˜์—์„œ์˜ ์ ˆ๋Œ€ ๊ฐ๋„๋Š” theta1_ft + theta2๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉํ–ฅ์œผ๋กœ link2๋งŒํผ ๋” ๋‚˜์•„๊ฐ„ ์ง€์ ์ด ํŽœ ๋ ์ขŒํ‘œ ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ๋กœ {x : x3, y : y3}๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

inverseKinematics2DOF(targetX, targetY, prevJ1Deg, prevJ2Deg)

์ด ํ•จ์ˆ˜๋Š” ๋ชฉํ‘œ ํŽœ ์ขŒํ‘œ(targetX, targetY)๋ฅผ ์ฃผ๋ฉด, ํ•ด๋‹น ์ง€์ ์— ํŽœ์ผ ์œ„์น˜์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋‘ ๊ด€์ ˆ ๊ฐ๋„(joint1, joint2)๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. 2DOF ํ‰๋ฉด ๋กœ๋ด‡ ํŒ” ํ‘œ์ค€ ์—ญ๊ธฐ๊ตฌํ•™ ๊ณต์‹์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ๊ธฐ์กด ๊ฐ๋„์— ๊ฐ€๊นŒ์šด ๊ฐ๋„๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

๋ชฉํ‘œ ์  ๊นŒ์ง€ ๋ฒกํ„ฐ ๊ณ„์‚ฐ ๋ฐ ์ž‘์—… ๊ณต๊ฐ„ ์ฒดํฌ : ๋ชฉํ‘œ์ ๊นŒ์ง€ ์ƒ๋Œ€ ์ขŒํ‘œ๋กœ ๊ฑฐ๋ฆฌ(d)๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , | L1 - L2 | (์ตœ์†Œ ๊ฑฐ๋ฆฌ) ~ |L1 + L2| (์ตœ๋Œ€ ๊ฑฐ๋ฆฌ) ์•ˆ์— ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์—ญ ๊ธฐ๊ตฌํ•™ ๊ฐ๋„ ๊ณ„์‚ฐ : ๋ชฉํ‘œ์ ์ด ๋„๋‹ฌ ๊ฐ€๋Šฅ ํ•˜๋‹ค๋ฉด, ์‚ผ๊ฐ๋ฒ•์„ ์ด์šฉํ•ด ํŒ”๊ฟˆ์น˜ ๊ด€์ ˆ ๊ฐ๋„(theta2)๋ฅผ ๊ตฌํ•ฉ๋‹ˆ๋‹ค.

let cos2 = (d * d - L1 * L1 - L2 * L2) / (2 * L1 * L2); // ์‚ผ๊ฐ๋ฒ•์œผ๋กœ theta2 ๊ตฌํ•˜๊ธฐ

const theta2Abs = Math.acos(cos2); 
const theta2List = [theta2Abs, -theta2Abs]; // theta2 ํ›„๋ณด(theta2๋Š” ์•ˆ์œผ๋กœ ๊ตฝํžŒ ํŒ”, ๋ฐ”๊นฅ์œผ๋กœ ๊ตฝํžŒ ํŒ” ๋‘๊ฐ€์ง€์ž„.)

๊ตฌํ•œ ํŒ”๊ฟˆ์น˜ ๊ฐ๋„๋Š” ์ ˆ๋Œ€๊ฐ’์œผ๋กœ ๋‘๊ฐ€์ง€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ํŒ”๊ฟˆ์น˜๊ฐ€ ์•ˆ์ชฝ์œผ๋กœ ๊ตฝํžŒ ๊ฒฝ์šฐ์™€, ๋ฐ”๊นฅ์ชฝ์œผ๋กœ ๊ตฝํžŒ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

๊ฐ ํ›„๋ณด์— ๋Œ€ํ•ด theta1 ๊ตฌํ•˜๊ธฐ : ์—ญ๊ธฐ๊ตฌํ•™์„ ํ†ตํ•ด ์–ด๊นจ๊ด€์ ˆ์˜ ๊ฐ๋„ theta1๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

k1 = L1 + L2 * cos(theta2_fk)
k2 = L2 * sin(theta2_fk)

์ด ๊ฐ’๋“ค์€ ์—ญ๊ธฐ๊ตฌํ•™ ๊ณต์‹์—์„œ ์ค‘๊ฐ„ ๋‹จ๊ณ„๋กœ, ๋‘ ๋งํฌ์— ์˜ํ•ด ํ˜•์„ฑ๋œ ์‚ผ๊ฐํ˜•์—์„œ ์–ด๊นจ ๊ด€์ ˆ๊ณผ ๋ชฉํ‘œ์  ์‚ฌ์ด ๊ฐ๋„๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.

const theta1_fk = Math.atan2(dy, dx) - Math.atan2(k2, k1);

๋ฅผ ํ†ตํ•ด ๊ฐ๊ฐ theta2์— ๋Œ€ํ•œ ์ ˆ๋Œ€ ๊ฐ๋„ theta1_fk๋ฅผ ๊ตฌํ•˜๊ณ , offset ๋ฐ ์ด๋ฏธ์ง€ ๊ฐ๋„๋ฅผ ์ œ์™ธํ•œ ๊ธฐ์ค€ ์ž์„ธ ๊ธฐ์ค€(ใ„ท ์ž์„ธ ์‹œ joint1 : 0, joint2 : 0๋„) ๊ฐ๋„ theta1, theta2๋ฅผ ๊ตฌํ•ฉ๋‹ˆ๋‹ค.

ํ•ด ๊ฒฐ์ • : ์ดํ›„ ๊ฐ๊ฐ theta1, theta2์— ๋Œ€ํ•ด plotto์—์„œ ์ •์˜ํ•œ ์ตœ๋Œ€ ์ตœ์†Œ ๊ฐ๋„๋ฅผ ๋„˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์ œํ•œ ๊ฐ๋„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ๊ทธ ํ•ด๋Š” ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค.(aVaild ๋˜๋Š” bVaild = false)

์ดํ›„ ๋งŒ์•ฝ ๋‘˜ ๋‹ค ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด, ์ธ์ž๋กœ ๋ฐ›์€ prevJ1Deg์™€ prevJ2Deg๋ฅผ ์ด์šฉํ•ด ๋” ๊ฐ€๊นŒ์šด ๊ฐ๋„๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

buildFromSvgText(svgText, opts = {})

buildFromSvgText๋Š” svg ๊ฒฝ๋กœ ๋ฌธ์ž์—ด์„ ๋ฐ›์•„ ์ผ๋ จ์˜ ์ฒ˜๋ฆฌ๋ฅผ ๊ฑฐ์ฒ˜ ๋กœ๋ด‡ํŒ”์˜ ๊ฒฝ๋กœ ๋ฐ์ดํ„ฐ(#motionJson, #plot)๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž… ์„ค๋ช… ๊ธฐ๋ณธ๊ฐ’ / ๋น„๊ณ 
svgText string SVG ํŒŒ์ผ์˜ ์ „์ฒด ํ…์ŠคํŠธ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ํŒŒ์‹ฑ๋˜์–ด ๊ฒฝ๋กœ(path) ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ํ•„์ˆ˜
opts object SVG โ†’ ๋กœ๋ด‡ ๊ฒฝ๋กœ ๋ณ€ํ™˜ ๊ณผ์ •์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์˜ต์…˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์„ ํƒ
opts ์„ธ๋ถ€ ์˜ต์…˜
์˜ต์…˜๋ช… ํƒ€์ž… ์„ค๋ช… ๊ธฐ๋ณธ๊ฐ’ / ๋น„๊ณ 
k number ์ •๊ทœํ™”๋œ SVG ๋ฐ•์Šค๋ฅผ ๋กœ๋ด‡ ์ขŒํ‘œ๊ณ„๋กœ ๋งคํ•‘ํ•  ๋•Œ ์ ์šฉ๋˜๋Š” ์Šค์ผ€์ผ ๊ณ„์ˆ˜์ž…๋‹ˆ๋‹ค. 1.0
flipY boolean SVG ์ขŒํ‘œ๊ณ„์˜ Y์ถ•์„ ์ƒํ•˜ ๋ฐ˜์ „ํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. false
maxDeltaDeg number ํฌ์ธํŠธ ๊ฐ„ ํ—ˆ์šฉ๋˜๋Š” ์ตœ๋Œ€ ๊ด€์ ˆ ๊ฐ๋„ ๋ณ€ํ™”๋Ÿ‰(๋„ ๋‹จ์œ„)์ž…๋‹ˆ๋‹ค. this.MAX_DELTA_DEG

์‹คํ–‰ ๋™์ž‘

svg ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐ ์  ๋ฐฐ์—ด ์ถ”์ถœ : ๋งค๊ฐœ๋ณ€์ˆ˜ svgText๋ฅผ extractPathPointsFromSvg()๋ฅผ ํ†ตํ•ด ์  ๋ฐฐ์—ด์„ ์ถ”์ถœํ•˜์—ฌ, rawPts ๋ฐฐ์—ด์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ rawPts๋Š” {x,y,pen} ๊ฐ์ฒด๋“ค์˜ ๋ฐฐ์—ด๋กœ, svg ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์ƒ˜ํ”Œ๋ง ๋œ ์ ์„ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ขŒํ‘œ ์ •๊ทœํ™” : rawPts ๋ฐฐ์—ด์€ ์›๋ณธ SVG ์ขŒํ‘œ๊ณ„๋ฅผ ๋”ฐ๋ฅด๋Š” ์  ๋ฐฐ์—ด์ธ๋ฐ, ์ด๋ฅผ (0,0) ~ (SVG_BOX_SIZE,SVG_BOX_SIZE) ๋ฒ”์œ„์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, SVG_BOX_SIZE x SVG_BOX_SIZE ํฌ๊ธฐ์˜ ๋ฐ•์Šค์— ์ตœ๋Œ€ํ•œ ๊ฝ‰ ์ฐจ๊ฒŒ ์ถ•์†Œ/ํ™•๋Œ€ํ•˜๊ณ  ์œ„์น˜๋ฅผ ๋งž์ถฅ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ •๊ทœํ™”ํ•œ ์ขŒํ‘œ๋ฅผ ptsBox์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๋กœ๋ด‡ ์ขŒํ‘œ๊ณ„๋กœ ๋งคํ•‘ : ptsBox๋Š” (0,0) ~ (SVG_BOX_SIZE,SVG_BOX_SIZE)๋กœ ์ •๊ทœํšŒ ๋˜์–ด ์žˆ๋Š”๋ฐ,mapBoxToRobotTargets() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์‹œ์ž‘์„ 0,0์ด ์•„๋‹Œ baseX, baseY๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋„๋ก ํ‰ํ–‰์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ขŒํ‘œ๋ฅผ fitted ๋ฐฐ์—ด์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ๋„ ๋ณ€ํ™” ๊ธฐ๋ฐ˜ ๋ฆฌ์ƒ˜ํ”Œ๋ง : ๋กœ๋ด‡ํŒ”์˜ ์ขŒํ‘œ -> ์ขŒํ‘œ์˜ ์šด๋™ ๊ฐ๋™ ๋ณ€ํ™”๊ฐ€ #MAX_DELTA_DEG๋ณด๋‹ค ๋‚ฎ๊ฒŒ ๋ฆฌ์ƒ˜ํ”Œ๋ง ํ•˜๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด fitted ๋ฐฐ์—ด์— ์žˆ๋Š” ์ขŒํ‘œ๊ฐ€ ๋” ๋ฏธ์„ธํ•˜๊ฒŒ ๋ถ„ํ• ๋˜๋ฉฐ, ๋ถ„ํ• ๋œ ๋ฐฐ์—ด์ด fitted์— ๋‹ค์‹œ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ƒํƒœ ์ €์žฅ : fitted ๋ฐฐ์—ด์„ plotto.svgPathPoints์— ์ €์žฅํ•˜๊ณ , this.jsonBuilt = false๋กœ ์„ค์ •ํ•˜์—ฌ, ์•„์ง ์ด ์ƒˆ๋กœ์šด ๊ฒฝ๋กœ์— ๋Œ€ํ•œ motionJson์ด ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Œ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. motionJson ์ƒ์„ฑ : ๋งˆ์ง€๋ง‰์œผ๋กœ buildMotionJsonFromSvg() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, svgPathPoints๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋กœ๋ด‡ ํŒ”์˜ ์„ธ๋ถ€ ๋™์ž‘ ๋ช…๋ น ๋ชฉ๋ก์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. motionJson์ด ์™„์„ฑ๋˜๋ฉด, ๋‚ด๋ถ€์—์„œ plotEncode()๋ฅผ ์‚ฌ์šฉํ•ด ์ด ๋ช…๋ น๋“ค์„ ์ด์ง„ ํฌ๋งท์œผ๋กœ ์••์ถ•ํ•˜์—ฌ this.plot ์†์„ฑ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

buildMotionJsonFromSvg()

buildMotionJsonFromSvgํ•จ์ˆ˜๋Š” svgPathPoint๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„, ๋กœ๋ด‡ ํŒ” ๊ฐ ๊ด€์ ˆ์— ๋Œ€ํ•œ ์„ธ๋ถ€ ์›€์ง์ž„ ๋ช…๋ น ๋ฆฌ์ŠคํŠธ motionJson์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋กœ๋ด‡ํŒ”์ด ์ฒ˜์Œ ์œ„์น˜์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๊ฒฝ๋กœ์˜ ๋ชจ๋“  ์ ์„ ๋ฐฉ๋ฌธํ•˜๊ณ , ํŽœ์„ ์˜ฌ๋ฆฌ๊ฑฐ๋‚˜ ๋‚ด๋ฆฌ๋Š” ๋™์ž‘๊นŒ์ง€ ํฌํ•จํ•œ ๋ช…๋ น์ด ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. ์ด ๋–„, ๋ชจ๋“  ๋ช…๋ น์€ plotto์—์„œ ์ •์˜๋œ MAX_STEPS_PT๋ฅผ ๋„˜์ง€ ์•Š๋Š” ๋ช…๋ น์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

์ดˆ๊ธฐ ์„ค์ • ๋ฐ ์œ ํšจ์„ฑ ์ฒดํฌ : ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด this.jsonBulit๋ฅผ ํ™•์ธํ•˜์—ฌ, plotto ๊ฐ์ฒด์—์„œ motionJson์ด ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋งŒ๋“  ์ ์ด ์žˆ๋‹ค๋ฉด ๋‹ค์‹œ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋‹ค์Œ plotto motionJson ๋ฆฌ์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , curStepJ1, curStepJ2(ํ˜„์žฌ ๊ด€์ ˆ ์œ„์น˜๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ณ€์ˆ˜)๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ji ~ j2์˜ ๊ฐ๋„ ์ตœ๋Œ€์ตœ์†Œ ์Šคํƒญ์„ ๋‚˜ํƒ€๋‚ด๋Š” (j1MinStep ๋“ฑ) ๋ณ€์ˆ˜๋„ ์Šคํƒญ ๋‹จ์œ„๋กœ ๊ฐ๋„ ์ œํ•œ์„ ์ €์žฅํ•ด๋‘ก๋‹ˆ๋‹ค.

๋ณด์กฐ ํ•จ์ˆ˜ moveToTarget(targetJ1, targetJ2, penState)

์ด ๋‚ด๋ถ€ ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ๊ด€์ ˆ ์œ„์น˜์—์„œ ๋ชฉํ‘œ ๊ด€์ ˆ ์œ„์น˜(targetJ1, targetJ2)๊นŒ์ง€ ํŽœ ์ƒํƒœ penstate๋กœ ์ด๋™ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ d1,d2 ๋ช…๋ น์„ motionJson์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. totalDiff1 = targetJ1 - curStepJ1, totalDiff2 = targetJ2 - curStepJ2, maxDiff = max(|totalDiff1|, |totalDiff2|) ์‹์œผ๋กœ ๊ตฌํ•ด์„œ, ๋งŒ์•ฝ maxDiff๊ฐ€ 0์ด๋ฉด ํŽœ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฉด motionJson์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ , pen ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ๋งŒ motionJson์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

maxDiff๊ฐ€ 0์ด ์•„๋‹ˆ๋ผ๋ฉด, ์‹ค์ œ ์›€์ง์ž„์ด ํ•„์š”ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ, ํฐ ์›€์ง์ž„์„ ํ•œ๋ฒˆ์— ํ•˜์ง€ ์•Š๊ณ  MAX_STEPS_PT ์ดํ•˜์˜ ์ž‘์€ ๋‹จ๊ณ„๋กœ ์ชผ๊ฐœ์–ด ์—ฌ๋Ÿฌ ์›€์ง์ž„์œผ๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

rem1 = totalDiff1, rem2 = totalDiff2์œผ๋กœ ๋‚จ์€ ์ด๋™ ์Šคํ…์„ ์ €์žฅํ•˜๊ณ , ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด์„œ MAX_STEPS_PT๊นŒ์ง€ ์ž๋ฆ…๋‹ˆ๋‹ค. ์ดํ›„ $('pen').d = penState;๋กœ ํ˜„์žฌ ํŽœ ์ƒํƒœ๋ฅผ ์ง€์ •ํ•˜๊ณ , ๋ฐ˜๋ณต๋ฌธ ์•ˆ์—์„œ๋Š” ํŽœ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š์œผ๋ฉด์„œ, rem1๊ณผ rem2๊ฐ€ 0์ด ๋ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. ์ด moveToTarget ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ชจ๋“  d1, d2๊ฐ€ MAX_STEPS_PT ์ดํ•˜๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

ํ™ˆ ์œ„์น˜ -> ์ฒซ ๋ฒˆ์งธ ๊ฒฝ๋กœ ์  ์ด๋™ ๋กœ๋ด‡ํŒ”์ด ์ฒ˜์Œ์—๋Š” ํ™ˆ ์œ„์น˜(Joint1 : 0๋„, Joint2 : 0๋„)์—์„œ ์‹œ์ž‘ํ•œ๋‹ค ๊ฐ€์ •ํ•˜๊ณ , ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ ์ง„ํ–‰ํ•˜๋Š” ์ผ์€ svgPathPoints[0]์„ ๊ฐ€์ ธ์™€์„œ, inverseKinematics2DOF()ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ผ ์ž…๋‹ˆ๋‹ค. inverseKinematics2DOF()์‹œ, ์ฒ˜์Œ ์ ์—์„œ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ, prevJ1=0, prevJ2=0์œผ๋กœ ์—ญ๊ธฐ๊ตฌํ•™ ๊ณ„์‚ฐ์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์–ป์€ ๊ฐ๋„ ๊ฐ’์„ firstIk์— ๋ฐ˜ํ™˜ํ•˜์—ฌ, firstIK๋ฅผ STEP ๋‹จ์œ„๋กœ ๋ณ€ํ™˜ ํ›„, penState = 0(์‹œ์ž‘ํ• ๋•Œ ์ด๋ฏ€๋กœ)๋กœ moveToTarget() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์ด ํ˜ธ์ถœ๋กœ ์ธํ•ด ํ™ˆ ์œ„์น˜์—์„œ ์ฒซ ์ ์˜ ์Šคํƒญ๊นŒ์ง€์˜ ๋ช…๋ น์ด plotto.motionJson์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๊ณ„์‚ฐํ•œ ๊ฐ๋„๋ฅผ prevJ1Deg, prevJ2Deg์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์  ์ด๋™ : ์ด์ œ svgPathPoint์˜ ๋ชจ๋“  ์ ์„ ์ฐจ๋ก€๋Œ€๋กœ ์ˆœํšŒํ•˜๋ฉฐ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. for (let idx = 0; idx < totalPoints; idx++) ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด ์ˆœํšŒํ•ฉ๋‹ˆ๋‹ค. svgPathPoint์—์„œ ์ขŒํ‘œ๋ฅผ ์–ป์–ด, inverseKinematics2DOF() -> moveToTarget() ๋ฅผ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, curStepJ1, curStepJ2, prevJ1Deg, prevJ2Deg๋„ ์—…๋ฐ์ดํŠธ ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ : ๋ฃจํ”„๊ฐ€ ๋๋‚œ ํ›„, prevPen !==0(ํŽœ์ด ๋‚ด๋ ค์ง„ ์ƒํƒœ)๋ผ๋ฉด ํŽœ์„ ์˜ฌ๋ฆฌ๋Š” ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.this.motionJson.push({ d1: 0, d2: 0, pen: 0 }) ์ดํ›„ this.plot = plotEncode(this.motionJson);๋ฅผ ํ†ตํ•ด motionJson์„ plot์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค(1 byte ํ˜•ํƒœ)

initLinkGeometry()

๋กœ๋ด‡ ํŒ” ์ด๋ฏธ์ง€์— ์ •์˜๋œ ๊ธฐ์ค€ ์ขŒํ‘œ๋ฅผ ์ด์šฉํ•ด ์ƒ๋ถ€ ํŒ”(link1)๊ณผ ํ•˜๋ถ€ ํŒ”(link2)์˜ ๊ธธ์ด์™€ ๊ธฐ์ค€ ์ž์„ธ ๊ฐ๋„(rest angle)๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ณ„์‚ฐ๋œ ๊ฐ’๋“ค์€ ์ดํ›„ ์ •ยท์—ญ๊ธฐ๊ตฌํ•™ ๊ณ„์‚ฐ ์‹œ ์ด๋ฏธ์ง€ ๊ธฐ์ค€๊ณผ ์‹ค์ œ ๊ด€์ ˆ ๊ฐ๋„ ๊ฐ„์˜ ๋ณด์ •๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

์ƒ๋ถ€ ํŒ” ๊ธธ์ด ๊ตฌํ•˜๊ธฐ : UPPER_JOINT_BASE์™€ UPPER_JOINT_ELBOW ์ขŒํ‘œ ๊ฐ„์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ link1 ๊ธธ์ด๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, scale์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ƒ๋ถ€ ํŒ” ์ด๋ฏธ์ง€ ๊ฐ๋„ ๊ตฌํ•˜๊ธฐ : ๋‘ ์ ์„ ์—ฐ๊ฒฐํ•˜๋Š” ์„ ์˜ ๋ฐฉํ–ฅ์„ atan2๋กœ ๊ณ„์‚ฐํ•˜์—ฌ upperRestAngle๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋ถ€ ํŒ” ๊ธธ์ด ๊ตฌํ•˜๊ธฐ : FORE_JOINT_ELBOW์™€ FORE_PEN ์ขŒํ‘œ ๊ฐ„์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ link2 ๊ธธ์ด๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.์ด ๋•Œ, scale์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋ถ€ ํŒ” ์ด๋ฏธ์ง€ ๊ฐ๋„ ๊ตฌํ•˜๊ธฐ : ๋‘ ์ ์„ ์—ฐ๊ฒฐํ•˜๋Š” ์„ ์˜ ๋ฐฉํ–ฅ์„ atan2๋กœ ๊ณ„์‚ฐํ•˜์—ฌ foreRestAngle๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

3. ๊ฐ์ฒด ์ •์˜

4. ์ฃผ์š” ํ•จ์ˆ˜

normalizeAngle(angle)

์ฃผ์–ด์ง„ ๊ฐ๋„๋ฅผ โ€“180ยฐ ~ 180ยฐ ๋ฒ”์œ„๋กœ ์ •๊ทœํ™”ํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

์ž…๋ ฅ๋œ ๊ฐ๋„๊ฐ€ 180ยฐ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด 360ยฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋นผ์„œ ๋ฒ”์œ„ ์•ˆ์œผ๋กœ ๋งž์ถฅ๋‹ˆ๋‹ค. ์ž…๋ ฅ๋œ ๊ฐ๋„๊ฐ€ -180ยฐ๋ณด๋‹ค ์ž‘์œผ๋ฉด 360ยฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋”ํ•ด ๋ฒ”์œ„ ์•ˆ์œผ๋กœ ๋งž์ถฅ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ชจ๋“  ๊ฐ๋„๋ฅผ ๋™์ผํ•œ ๊ธฐ์ค€ ๋ฒ”์œ„๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๊ฐ๋„ ๋น„๊ต๋‚˜ ๋ณด๊ฐ„ ์‹œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ถˆ์—ฐ์† ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

extractPathPointsFromSvg(svgText, opts = {})

extractPathPointsFromSvg(svgText, opts={}) ํ•จ์ˆ˜๋Š” SVG ์ด๋ฏธ์ง€ ์†Œ์Šค (svgText)๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„, ๊ทธ ์•ˆ์— ํฌํ•จ๋œ ๋ชจ๋“  ๋„ํ˜•(graphic element)๋“ค์˜ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์ผ์ • ๊ฐ„๊ฒฉ์˜ ์ ๋“ค์„ ์ถ”์ถœํ•˜๊ณ  ์ด๋ฅผ ์ขŒํ‘œ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋งค๊ฐœ ๋ณ€์ˆ˜

์ด ํ•จ์ˆ˜๋Š” ๋‘๊ฐœ์˜ ์ธ์ˆ˜๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. svgText : SVG ํŒŒ์ผ์˜ ์›๋ณธ ํ…์ŠคํŠธ ์ž…๋‹ˆ๋‹ค. SVG๋ฅผ ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•˜๋ฉด, ํ•จ์ˆ˜๊ฐ€ ์ด๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ DOM ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. opts : ๊ฒฝ๋กœ ์ถ”์ถœ๊ณผ ์ƒ˜ํ”Œ๋ง ์˜ต์…˜์„ ๋‹ด์€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ {}์ด๋ฉฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์†์„ฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

opts ์˜ต์…˜
์˜ต์…˜ ์ด๋ฆ„ ํƒ€์ž… / ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
sampleStep number / null ์ƒ˜ํ”Œ๋ง ๊ฐ„๊ฒฉ๋ฅผ ์ง์ ‘ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ’์ด ์ฃผ์–ด์ง€๋ฉด ๊ฐ ๊ฒฝ๋กœ๋ฅผ ๊ณ ์ •๋œ ๊ฐ„๊ฒฉ์œผ๋กœ ์ƒ˜ํ”Œ๋งํ•˜๋ฉฐ, samplesPerPath์„ค์ •์€ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.
samplesPerPath number / 200 ๊ฐ ๋„ํ˜•์˜ ๊ฒฝ๋กœ๋ฅผ ๋ช‡ ๋“ฑ๋ถ„์œผ๋กœ ๋‚˜๋ˆŒ์ง€์— ๋Œ€ํ•œ ๋Œ€๋žต์ ์ธ ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค. ๊ฒฝ๋กœ ์ „์ฒด๋ฅผ ์ด ๊ฐ’์œผ๋กœ ๋‚˜๋ˆ„์–ด ํ‰๊ท  ๊ฐ„๊ฒฉ์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
maxStepClamp number / 2 ์ƒ˜ํ”Œ ๊ฐ„๊ฒฉ์˜ ์ƒํ•œ๊ฐ’์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๊ธด ๊ฒฝ๋กœ์˜ ๊ฒฝ์šฐ ๊ฐ„๊ฒฉ์ด ์ง€๋‚˜์น˜๊ฒŒ ์ปค์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ’์œผ๋กœ, ๊ฐ„๊ฒฉ์ด ์ด๋ณด๋‹ค ํฌ๋‹ค๋ฉด ์ด ๊ฐ’์œผ๋กœ ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค.
maxSamplesPerPath number / 3000 ๊ฐ ๊ฒฝ๋กœ๋‹น ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ์ƒ˜ํ”Œ ์  ๊ฐฏ์ˆ˜์ž…๋‹ˆ๋‹ค.
bridgeScale number / 1.0 path๊ฐ„ ์ด๋™ ๊ฒฝ๋กœ์˜ ๋ฐ€๋„๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์Šค์ผ€์ผ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.

opts๋ฅผ ํ†ตํ•ด ๊ฒฝ๋กœ ์ƒ˜ํ”Œ๋ง ๊ฐ„๊ฒฉ๊ณผ ๋ฐ€๋„๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

SVG ํŒŒ์‹ฑ ๋ฐ ์ดˆ๊ธฐ ์„ค์ •

DOM ๊ฐ์ฒด ์ƒ์„ฑ : ํ•จ์ˆ˜๋Š” ์ฃผ์–ด์ง„ SVG ํ…์ŠคํŠธ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ DOM ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, DOM ํŒŒ์„œ๋ฅผ์ด์šฉํ•˜์—ฌ ์‹ค์ œ SVG DOM ๊ฐ์ฒด๋กœ(doc)๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ž„์‹œ SVG ์—˜๋ฆฌ๋จผํŠธ ์ƒ์„ฑ : ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™” : ์ตœ์ข…์œผ๋กœ ๋ฐ˜ํ™˜ํ•  ๋ฐฐ์—ด์ธ points๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.(point์—๋Š” {x, y, pen} ๊ฐ์ฒด๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์Œ“์ž…๋‹ˆ๋‹ค.) ๋˜ํ•œ, ์ด์ „ ๋„ํ˜•์˜ ๋งˆ์ง€๋ง‰์„ ์ €์žฅํ•˜๋Š” lastGlobalPt๋„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.(์ฒซ ๋„ํ˜• ํ›„์— ๊ฐ’์„ ์ฑ„์›๋‹ˆ๋‹ค.), ์ด ๊ฐ’์€ path ๊ฐ„ ์ด๋™ ๊ฒฝ๋กœ๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ณ€ํ™˜ ํ–‰๋ ฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ

SVG ์š”์†Œ๋“ค์€ transfrom ์†์„ฑ์„ ํ†ตํ•ด ํ‰ํ–‰์ด๋™, ํšŒ์ „, ์Šค์ผ€์ผ, ๊ธฐ์šธ์ด๊ธฐ(skew)๋“ฑ์˜ ๋ณ€ํ™˜์„ ๊ฐ€์ง€๋ฉฐ, <g> ๊ทธ๋ฃน์„ ์ด์šฉํ•ด์„œ ์ƒ์œ„ ๊ทธ๋ฃน๋“ค์˜ ๋ณ€ํ™˜์ด ๋ˆ„์  ์ ์šฉ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. spine ์ฝ”๋“œ์—์„  ์ด๋Ÿฌํ•œ ๋ณ€ํ™˜์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€ํ™˜ affine ํ–‰๋ ฌ์„ ์ด์šฉํ•ด์„œ ์ขŒํ‘œ๊ณ„ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•˜๋ฉฐ, ์ด ํ–‰๋ ฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜์— ๋Œ€ํ•ด ์†Œ๊ฐœํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

I()

ํ•ญ๋“ฑ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค(a=1, d=1์ด๊ณ  ๋‚˜๋จธ์ง€ 0์ธ ๋‹จ์œ„ํ–‰๋ ฌ)

T(tx, ty)

์ด๋™ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. x๋ฐฉํ–ฅ tx, y ๋ฐฉํ–ฅ ty๋งŒํผ ํ‰ํ–‰์ด๋™ ์‹œํ‚ค๋Š” ํ–‰๋ ฌ์ž…๋‹ˆ๋‹ค.

S(sx, sy)

์Šค์ผ€์ผ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. x์ถ• ๋ฐฉํ–ฅ sx๋ฐฐ y์ถ• ๋ฐฉํ–ฅ sy๋ฐฐ ํ™•๋Œ€/์ถ•์†Œ ํ•ฉ๋‹ˆ๋‹ค.

R(deg)

ํšŒ์ „ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ๊ฐ๋„ ๋งŒํผ ์›์ ์„ ์ค‘์‹ฌ์œผ๋กœ ํšŒ์ „ํ•˜๋Š” ํ–‰๋ ฌ์ž…๋‹ˆ๋‹ค.

KX(deg)

X์ถ• ๊ธฐ์ค€ ๊ธฐ์šธ์ด๊ธฐ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ๊ฐ๋„ ๋งŒํผ x์ถ• ๋ฐฉํ–ฅ์œผ๋กœ ๊ธฐ์šธ์ด๋Š” ๋ณ€ํ™˜์ž…๋‹ˆ๋‹ค.

KY(deg)

Y์ถ• ๊ธฐ์ค€ ๊ธฐ์šธ์ด๊ธฐ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ๊ฐ๋„ ๋งŒํผ y์ถ• ๋ฐฉํ–ฅ์œผ๋กœ ๊ธฐ์šธ์ด๋Š” ๋ณ€ํ™˜์ž…๋‹ˆ๋‹ค.

multiplyMatrices(m1, m2)

๋‘๊ฐœ์˜ ํ–‰๋ ฌ m1,m2๋ฅผ ๋ฐ›์•„ ์ˆœ์„œ๋Œ€๋กœ ํ•ฉ์„ฑํ•œ ๊ฒฐ๊ณผ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

parseTransform(transformStr)

"translate(...)", "rotate(...)"์™€ ๊ฐ™์€ SVG transform ์†์„ฑ ๋ฌธ์ž์—ด์„ ์ฝ์–ด๋“ค์ด๊ณ , ๊ทธ ๋ณ€ํ™˜๋“ค์˜ ํ•ฉ์„ฑ ๊ฒฐ๊ณผ๋ฅผ ํ•˜๋‚˜์˜ ํ–‰๋ ฌ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ •๊ทœ์‹์œผ๋กœ "์ด๋ฆ„" ํŒจํ„ด์„ ์ฐพ์•„์„œ ๊ฐ ๋ณ€ํ™˜๋ช…๋ น์„ ์ˆœ์„œ๋Œ€๋กœ ํ•ด์„ํ•˜๋ฉฐ, ์•ž์„œ ์ •์˜ํ•œ ํ–‰๋ ฌ ํ•จ์ˆ˜๋“ค์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ฐ ๋ณ€ํ™˜ ํ–‰๋ ฌ m์„ ์ด์ „๊นŒ์ง€์˜ ๋ˆ„์  ํ–‰๋ ฌ M์— ๊ณฑ์…ˆํ•˜๋ฉฐ ํ•ฉ์„ฑํ•ด ๋‚˜๊ฐ‘๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด transform ๋ฌธ์ž์—ด์— ๋‚˜์—ด๋œ ๋ณ€ํ™˜์ด ์ˆœ์ฐจ ์ ์šฉ๋œ ์ตœ์ข… ํ–‰๋ ฌ M์„ ์–ป๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

getAccumulatedTransformInclusive(el)

<g>๊ทธ๋ฃน์— ์†ํ•œ svg๋Š” ์ž์‹ ์˜ transform์„ ํฌํ•จํ•˜์—ฌ ๋ถ€๋ชจ๋ฅผ ๋”ฐ๋ผ ์ตœ์ƒ์œ„ svg๊นŒ์ง€ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ๋ชจ๋“  ๋ณ€ํ™˜์„ ํ•ฉ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์š”์†Œ ์ž์ฒด -> ๋ถ€๋ชจ์˜ ๋ณ€ํ™˜ .. ์ˆœ์œผ๋กœ ๋ชจ๋‘ ๊ณฑํ•œ ์ „์ฒด ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

getAccumulatedTransformParentsOnly(el)

<use> ์š”์†Œ๋ฅผ ๊ตฌํ•  ๋•Œ, ์ž๊ธฐ ์ž์‹ ์˜ transform์„ ์ ์šฉํ•˜๊ธฐ ์ „ ์ƒ์œ„ ์š”์†Œ์˜ transform์„ ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์š”์†Œ ์ž์ฒด์˜ ๋ณ€ํ™˜์„ ์ œ์™ธํ•˜๊ณ  ๋ถ€๋ชจ๋“ค์˜ ๋ˆ„์  ๋ณ€ํ™˜์„ ๊ตฌํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

shouldRender(el)

์‹ค์ œ๋กœ ๊ทธ๋ ค์ง€์ง€ ์•Š๋Š” ์š”์†Œ๋ฅผ ์ œ์™ธํ•˜๋Š” ํ•„ํ„ฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, <defs>, display="none"์™€ ๊ฐ™์€ ์š”์†Œ๋Š” ๊ทธ๋ ค์ง€์ง€ ์•Š๋Š” ์š”์†Œ์ธ๋ฐ, ์ด์™€ ๊ฐ™์€ ๊ฒƒ์„ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜ํ”ฝ ์š”์†Œ

SVG ๋‚ด๋ถ€์˜ ๊ฐ ๋„ํ˜• ์š”์†Œ๋“ค์„ ์ˆ˜์ง‘ํ•˜๊ณ , ๊ฐ ์š”์†Œ ๋ณ„๋กœ ๊ฒฝ๋กœ ์ •๋ณด๋ฅผ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, ํฌ๊ฒŒ ๋‘๊ฐ€์ง€ ์š”์†Œ๋ฅผ ๋‹ค๋ฃจ๋Š”๋ฐ, ์ง์ ‘์ ์ธ ๊ทธ๋ž˜ํ”ฝ ์š”์†Œ(path์™€ ๊ธฐ๋ณธ ๋„ํ˜•)์™€ <use>์ฐธ๊ณ  ์š”์†Œ ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๊ทธ๋ž˜ํ”ฝ ์š”์†Œ ์ฒ˜๋ฆฌ svgRoot.querySelectorAll("path, circle, rect, ellipse, line, polygon, polyline")๋ฅผ ์ด์šฉํ•˜์—ฌ svg ๋‚ด ๋ชจ๋“  ๊ธฐ๋ณธ ๊ทธ๋ž˜ํ”ฝ ์š”์†Œ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, shouldRender(el)๋ฅผ ํ†ตํ•ด ๋ Œ๋”๋ง ๋Œ€์ƒ์ธ์ง€ ํ™•์ธํ•˜๊ณ , ๋งž๋‹ค๋ฉด allElements ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, ์ถ”๊ฐ€ ์‹œ์— ์š”์†Œ์˜ ์ •๋ณด๋„ ๊ฐ™์ด ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

 	allElements.push({
    element: el, // ์š”์†Œ
    transform: getAccumulatedTransformInclusive(el), // ๋ˆ„์  ๋ณ€ํ™˜ ํ–‰๋ ฌ
    tagName: el.tagName.toLowerCase() // ํƒœ๊ทธ ๋ช…
});

<use> ์š”์†Œ ์ฒ˜๋ฆฌ svg์—์„œ๋Š” <use xlink:href="#id">์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์‚ฌ์ „์— ์ •์˜๋œ ๋„ํ˜•์„ ๋ณต์‚ฌํ•˜์—ฌ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. <use> ์š”์†Œ๋Š” ์ž์‹ ์˜ ์œ„์น˜(x, y ์†์„ฑ)์™€ ๋ณ€ํ™˜(transform ์†์„ฑ)์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฐธ์กฐ ๋Œ€์ƒ ์š”์†Œ์˜ ์ •์˜ ๋ณ€ํ™˜๊นŒ์ง€ ํ•ฉ์ณ์ ธ์„œ ์ตœ์ข… ์œ„์น˜๊ฐ€ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„  svgRoot.querySelectorAll("use")๋ฅผ ํ†ตํ•ด ๋ชจ๋“  <use>์š”์†Œ๋ฅผ ์ฐพ์€ ๋’ค, shouldRender(useEl)๋กœ ํ™•์ธํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ <use>์— ๋Œ€ํ•ด resolveUseElement(useEl) ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‹ค์ œ ์ฐธ์กฐ๋œ ์›๋ณธ ์š”์†Œ์™€ ๊ทธ ๋ณ€ํ™˜ ์ •๋ณด๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

resolveUseElement(useEl) ํ•จ์ˆ˜

์ด ํ•จ์ˆ˜๋Š” <use> ์š”์†Œ์˜ ์›๋ณธ ๋„ํ˜• + ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ ๋ณ€ํ™˜์„ ๋ชจ๋‘ ํ•ด์„ํ•ด ํ•˜๋‚˜์˜ ์‹ค์ œ ๋„ํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค ๋ Œ๋”๋ง ๋Œ€์ƒ์— ํฌํ•จ์‹œํ‚ค๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค. <use>์˜ href ์†์„ฑ์—์„œ ์ฐธ์กฐ ๋Œ€์ƒ ์ถ”์ถœ : <use> ์š”์†Œ์˜ href ๋˜๋Š” xlink:href ๊ฐ’์„ ์ฝ์–ด #id ํ˜•ํƒœ์˜ ์ฐธ์กฐ ๋Œ€์ƒ id๋ฅผ ์ถ”์ถœํ•˜๊ณ , svgRoot.querySelector('#id')๋กœ ์›๋ณธ ๊ทธ๋ž˜ํ”ฝ ์š”์†Œ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์›๋ณธ ์š”์†Œ ์กด์žฌ ํ™•์ธ : ๋งŒ์•ฝ ์ฐธ์กฐ๋œ id์— ํ•ด๋‹น ์›๋ณธ ์š”์†Œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด, ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.

<use>์š”์†Œ์˜ x, y ์†์„ฑ์„ ํ‰ํ–‰์ด๋™ ํ–‰๋ ฌ๋กœ ๋ณ€ํ™˜ : <use> ์š”์†Œ์˜ x,y ์†์„ฑ์„ ์ฝ์–ด (x,y)๋กœ ์ด๋™์‹œํ‚ค๋Š” ํ‰ํ–‰์ด๋™ ํ–‰๋ ฌ T๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ณ€ํ™˜ ํ–‰๋ ฌ ์ˆ˜์ง‘ : <use>๋กœ ์ธํ•ด ์ ์šฉ๋˜๋Š” ๋ชจ๋“  ๋ณ€ํ™˜์„ ๋‹ค์Œ ๋„ค๊ฐ€์ง€ ์ข…๋ฅ˜๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ๋ถ„ ์„ค๋ช…
๋ถ€๋ชจ ๊ทธ๋ฃน ๋ณ€ํ™˜ <use> ์š”์†Œ์˜ ์ƒ์œ„ <g> ์š”์†Œ๋“ค์— ์ ์šฉ๋œ transform์„ ๋ˆ„์ ํ•œ ๋ณ€ํ™˜ ํ–‰๋ ฌ
<use> ์ž์ฒด ๋ณ€ํ™˜ <use> ์š”์†Œ์— ์ง์ ‘ ์ง€์ •๋œ transform ์†์„ฑ์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋œ ๋ณ€ํ™˜ ํ–‰๋ ฌ
<use> ์œ„์น˜ ์ด๋™ <use> ์š”์†Œ์˜ x, y ์†์„ฑ์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋œ ํ‰ํ–‰์ด๋™(translate) ํ–‰๋ ฌ
์›๋ณธ ์š”์†Œ ๋ณ€ํ™˜ <use>๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ์›๋ณธ ๊ทธ๋ž˜ํ”ฝ ์š”์†Œ(ref)์— ์ ์šฉ๋œ transform ์†์„ฑ์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋œ ๋ณ€ํ™˜ ํ–‰๋ ฌ

์ตœ์ข… ๋ณ€ํ™˜ ํ–‰๋ ฌ ํ•ฉ์„ฑ : ์ˆ˜์ง‘๋œ ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ๋ถ€๋ชจ -> <use> -> x,y ์ด๋™ -> ์›๋ณธ ์š”์†Œ ๋ณ€ํ™˜ ์ˆœ์œผ๋กœ ์ ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ํ–‰๋ ฌ๋กœ ํ•ฉ์„ฑํ•ฉ๋‹ˆ๋‹ค.

<use> ํ•ด์„ ๊ฒฐ๊ณผ ๊ฐ์ฒด ์ƒ์„ฑ : ํ•ด์„๋œ <use> ์š”์†Œ์— ๋Œ€ํ•ด ๋‹ค์Œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋ Œ๋”๋ง ๋Œ€์ƒ์— ์ถ”๊ฐ€ : ์œ„์—์„œ ํ•ด์„๋œ ๊ฐ์ฒด๋ฅผ allElements ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•˜์—ฌ, ๋ Œ๋”๋ง ์ฒ˜๋ฆฌ์— ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

์ด ๋‹จ๊ณ„๊นŒ์ง€ ์™”๋‹ค๋ฉด, allElements ๋ฐฐ์—ด์—๋Š” SVG ๋‚ด ๋ชจ๋“  ์ฒ˜๋ฆฌ ๋Œ€์ƒ ๋„ํ˜•์ด ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ํ˜•์„ ๊ฒฝ๋กœ ๋ฐ์ดํ„ฐ(path)๋กœ ๋ณ€ํ™˜

SVG๋‚ด์—๋Š” path ์š”์†Œ ์™ธ์—๋„ <circle>,<rect> ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋ณธ ๋„ํ˜•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜์—์„œ๋Š” ๋ชจ๋“  ๋„ํ˜•์„ path ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

circleToPathLocal(cx,cr,y)

์›์€ path๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ๋‘๊ฐœ์˜ ํ˜ธ๋กœ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. svg path์˜ A(์›ํ˜ธ) ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ ๋‘๊ฐœ์˜ ํ˜ธ๋กœ ์›์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. <circle>์š”์†Œ์˜ cx, cy, r ์†์„ฑ์„ ์ฝ์–ด ์ค‘์‹ฌ ์ขŒํ‘œ์™€ ๋ฐ˜์ง€๋ฆ„์„ ์–ป์Šต๋‹ˆ๋‹ค. ์›์˜ ๊ฐ€์žฅ ์™ผ์ชฝ ์  (cx-r, cy)์—์„œ M ๋ช…๋ น์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ A r r 0 1 1 ๋ช…๋ น์œผ๋กœ ์˜ค๋ฅธ์ชฝ ์  (cx + r, cy)๊นŒ์ง€ ๋ฐ˜์›์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. ์ดํ›„ ๋‘ ๋ฒˆ์งธ A r r 0 1 1 ๋ช…๋ น์œผ๋กœ ๋‹ค์‹œ ์‹œ์ž‘์  (cx - r, cy)๊นŒ์ง€ ๋ฐ˜์›์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์— Z ๋ช…๋ น์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋‹ซ์•„ ํ•˜๋‚˜์˜ ์™„์ „ํ•œ ์› path๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์œผ๋กœ ๋‘๊ฐœ์˜ ํ˜ธ๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด ํ•˜๋‚˜์˜ ์› ๊ฒฝ๋กœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

ellipseToPathLocal(cx, cy, rx, ry)

ํƒ€์›์€ circle๊ณผ ๊ฑฐ์˜ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ ๋˜๋ฉฐ, XยทY ๋ฐฉํ–ฅ ๋ฐ˜์ง€๋ฆ„์ด ์„œ๋กœ ๋‹ค๋ฅธ ์›์œผ๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. <ellipse> ์š”์†Œ์˜ cx, cy, rx, ry ์†์„ฑ์„ ์ฝ์Šต๋‹ˆ๋‹ค. ์ดํ›„ (cx - rx, cy)์—์„œ M ๋ช…๋ น์œผ๋กœ ์‹œ์ž‘ํ•˜๋ฉฐ, A rx ry 0 1 1 ๋ช…๋ น์œผ๋กœ (cx + rx, cy)๊นŒ์ง€ ๋ฐ˜์›์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. ๋‹ค์‹œ A rx ry 0 1 1 ๋ช…๋ น์œผ๋กœ ์‹œ์ž‘์ ๊นŒ์ง€ ์ด์–ด์ค๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ Z ๋ช…๋ น์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋‹ซ์•„ ํ•˜๋‚˜์˜ ํƒ€์› path๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

rectToPathLocal(x, y, width, height, rx, ry)

์‚ฌ๊ฐํ˜•์€ rx, ry(๋ชจ์„œ๋ฆฌ ๋ฐ˜๊ฒฝ)์— ๋”ฐ๋ผ ๋‘๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๊ณตํ†ต ์ฒ˜๋ฆฌ x, y, width, height, rx, ry ์†์„ฑ์„ ์ฝ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ rx, ry๊ฐ€ ์—†์œผ๋ฉด 0์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , ํ•˜๋‚˜๋งŒ ์ง€์ •๋œ ๊ฒฝ์šฐ ๋‘ ๊ฐ’์„ ๋™์ผํ•˜๊ฒŒ ๋งž์ถฅ๋‹ˆ๋‹ค. ๋˜ํ•œ, rx > width / 2 ์ด๋ฉด width / 2๋กœ ์ œํ•œํ•˜๊ณ , ry > height / 2 ์ด๋ฉด height / 2๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

๋ชจ์„œ๋ฆฌ๊ฐ€ ๋‘ฅ๊ทผ ์‚ฌ๊ฐํ˜•(rx > 0 && ry > 0) rx > 0 ์ด๊ณ  ry > 0 ์ธ ๊ฒฝ์šฐ, ๊ฐ ๋ชจ์„œ๋ฆฌ๋ฅผ ํƒ€์› 1/4 ํ˜ธ์— ๊ทผ์‚ฌํ•œ ๋ฒ ์ง€์–ด ๊ณก์„ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์›์˜ 1/4์„ ํ๋น… ๋ฒ ์ง€์–ด๋กœ ๊ทผ์‚ฌํ•˜๊ธฐ ์œ„ํ•ด K = 0.5522847498307936 ์ƒ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ๊ฐ ๋ชจ์„œ๋ฆฌ์— ๋Œ€ํ•ด ox = rx * K, oy = ry * K ๊ฐ’์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. ์ง์„ (L)๊ณผ ํ๋น… ๋ฒ ์ง€์–ด(C) ๋ช…๋ น์„ ์กฐํ•ฉํ•˜์—ฌ ๋„ค ๋ชจ์„œ๋ฆฌ๋ฅผ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋„ค ๋ชจ์„œ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์—ฐ๊ฒฐํ•œ ํ›„ Z ๋ช…๋ น์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค.

์ด ๊ฒฐ๊ณผ, ์›๋ž˜ rect์˜ ๋‘ฅ๊ทผ ๋ชจ์„œ๋ฆฌ๋ฅผ rx, ry ๋ฐ˜์ง€๋ฆ„์˜ ํƒ€์› ํ˜ธ์— ๊ทผ์ ‘ํ•œ path๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ์„œ๋ฆฌ๊ฐ€ ์ง๊ฐ์ธ ์‚ฌ๊ฐํ˜•(rx <=1e-9 && ry <=1e-9) M x,y๋กœ ์‹œ์ž‘ํ•œ ๋’ค, ์‹œ๊ณ„ ๋ฐฉํ–ฅ์œผ๋กœ ๋„ค ๊ฐœ์˜ L ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด ๊ผญ์ง“์ ์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์— Z ๋ช…๋ น์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋‹ซ์•„ ๋‹จ์ˆœ ์‚ฌ๊ฐํ˜• path๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

lineToPathLocal(x1, y1, x2, y2)

<line> ์š”์†Œ๋Š” ์‹œ์ž‘์  (x1, y1)๊ณผ ๋์  (x2, y2)์„ ๊ฐ€์ง€๋Š” ๋‹จ์ˆœ ์„ ๋ถ„์ž…๋‹ˆ๋‹ค. M x1,y1 โ†’ L x2,y2 ํ˜•ํƒœ์˜ path๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

polygonToPathLocal(points)

<polygon> ์š”์†Œ์˜ points ์†์„ฑ์„ ํŒŒ์‹ฑํ•˜์—ฌ ์ขŒํ‘œ ๋ฐฐ์—ด์„ ์–ป์Šต๋‹ˆ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ ์„ M ๋ช…๋ น์œผ๋กœ ์„ค์ •ํ•˜๋ฉฐ, ์ดํ›„ ๊ฐ ์ ๋งˆ๋‹ค L ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ง์„ ์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. polygon์€ ๋‹ซํžŒ ๋„ํ˜•์ด๋ฏ€๋กœ ๋งˆ์ง€๋ง‰์— Z ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฒฝ๋กœ๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค.

polylineToPathLocal(points)

<polygon> ์š”์†Œ์˜ points ์†์„ฑ์„ ํŒŒ์‹ฑํ•˜์—ฌ ์ขŒํ‘œ ๋ฐฐ์—ด์„ ์–ป์Šต๋‹ˆ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ ์„ M ๋ช…๋ น์œผ๋กœ ์„ค์ •ํ•˜๋ฉฐ, ์ดํ›„ ๊ฐ ์ ๋งˆ๋‹ค L ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ง์„ ์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. polygon์€ ์—ด๋ฆฐ ๊บพ์€ ์„ ์ด๋ฏ€๋กœ ๋งˆ์ง€๋ง‰์— Z ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฒฝ๋กœ๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค.

๊ฒฝ๋กœ ๊ธธ์ด ๊ณ„์‚ฐ

์ด์ œ ๋ชจ๋“  ์š”์†Œ์— ๋Œ€ํ•ด path ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜์—ˆ์œผ๋ฏ€๋กœ, ๊ฐ ๊ฒฝ๋กœ์˜ ๊ธธ์ด๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์นฉ๋‹ˆ๋‹ค. ๊ฐ ๊ฒฝ๋กœ์˜ ๊ธธ์ด๋ฅผ ๊ตฌํ•˜๋Š” ์ด์œ ๋Š”, ์  ์ƒ˜ํ”Œ๋ง ๊ฐ„๊ฒฉ์„ ๊ฒฐ์ •ํ•˜๊ณ  ์ตœ์ ํ™” ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ๋Š” ๋ชจ๋“  ์š”์†Œ์— ๋Œ€ํ•ด ๋‹ค์Œ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ prepared๋ผ๋Š” ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์— ๋ชจ์๋‹ˆ๋‹ค.

์ž„์‹œ path ์š”์†Œ ์ƒ์„ฑ : ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ์•ž์„œ ์–ป์–ด๋‘” path ๋ฐ์ดํ„ฐ ๋ฌธ์ž์—ด๊ณผ, ๋ˆ„์  ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ๊บผ๋ƒ…๋‹ˆ๋‹ค. ์ดํ›„ document.createElementNS(..., "path")๋กœ ์ƒˆ๋กœ์šด <path> ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ๊ฒฝ๋กœ ๋ฌธ์ž์—ด์„ d ์†์„ฑ์— ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ˆ„์  ๋ณ€ํ™˜ ํ–‰๋ ฌ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, ์ด path ์š”์†Œ์— ํ–‰๋ ฌ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ–‰๋ ฌ m์ด {a, b, c, d, e, f}๋ผ๋ฉด pathEl.setAttribute("transform", "matrix(a,b,c,d,e,f)") ํ˜•ํƒœ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด path๊ฐ€ ์‹ค์ œ ํ™”๋ฉด ์ขŒํ‘œ๊ณ„์—์„œ ๋ณ€ํ™˜๋œ ๋ชจ์–‘์œผ๋กœ ์ทจํ•ด์ง‘๋‹ˆ๋‹ค.

์ด path ์š”์†Œ๋ฅผ ์•„๊นŒ ๋งŒ๋“  tempSvg (์ˆจ๊ฒจ์ง„ SVG) ๋‚ด๋ถ€์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌ๋ฉด ๋ธŒ๋ผ์šฐ์ € ์—”์ง„์ด ํ•ด๋‹น path์˜ ๊ธธ์ด์™€ ๋ชจ์–‘์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๊ฒฝ๋กœ ๊ธธ์ด ์ธก์ • : pathEl.getTotalLength()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•ด๋‹น path (๋ณ€ํ™˜ ์ ์šฉ๋œ)์˜ ์ „์ฒด ๊ธธ์ด (L)๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๊ธธ์ด๊ฐ€ ์œ ํšจํ•˜๊ฒŒ ๊ณ„์‚ฐ๋œ ๊ฒฝ์šฐ (L > 0), ํ˜„์žฌ ์š”์†Œ์˜ ์ •๋ณด๋ฅผ prepared ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. prepared.push({ dAttr, transformMatrix, length: L });

์ด์ œ prepared์— ๊ฒฝ๋กœ ๋ฐ์ดํ„ฐ์™€ ๊ธธ์ด๊ฐ€ ๋ชจ์ด๊ฒŒ ๋˜๊ณ , ์ด ์ •๋ณด์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์  ์ƒ˜ํ”Œ๋ง์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์  ์ƒ˜ํ”Œ๋ง

prepared์— ๋‹ด๊ธด ๊ฐ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์ผ์ •ํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ์ ์„ ์ฐ์–ด points ๋ฐฐ์—ด์— ๋ˆ„์ ํ•ฉ๋‹ˆ๋‹ค. ์ƒ˜ํ”Œ๋ง ๋‹จ์œ„๋Š” opts์™€ ๊ฒฝ๋กœ์˜ ๊ธธ์ด์— ์˜ํ•ด ๊ฒฐ์ •๋˜๊ณ , ๊ฐ ๋„ํ˜•์˜ bridge ๋ถ€๋ถ„๋„ ํ•จ๊ป˜ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

์ƒ˜ํ”Œ๋ง ๋ฃจํ”„ ์‹œ์ž‘ :

์ƒ˜ํ”Œ๋ง ๊ฐ„๊ฒฉ ์„ค์ • : ์˜ต์…˜์œผ๋กœ sampleStep์ด ์ฃผ์–ด์กŒ๋‹ค๋ฉด, step = sampleStep์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. sampleStep์ด ์—†๋‹ค๋ฉด, ์ด ๊ฒฝ๋กœ์˜ ๊ธธ์ด๋ฅผ samplePerPath๋กœ ๋‚˜๋ˆˆ ๊ฐ’์œผ๋กœ step์„ ์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ, ์ด๋ ‡๊ฒŒ ๊ณ„์‚ฐํ•œ step์ด maxStepClamp๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ, step = maxStepClamp๋กœ ์ƒํ•œ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.(๋„ˆ๋ฌด ๊ฐ„๊ฒฉ์ด ์ปค์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€)

์ตœ๋Œ€ ์  ์ˆ˜ ์ œํ•œ : ๊ฒฝ๋กœ๊ฐ€ ๋งค์šฐ ๊ธธ์–ด์„œ step ๊ฐ„๊ฒฉ์œผ๋กœ ์ฐ์œผ๋ฉด ์  ๊ฐœ์ˆ˜๊ฐ€ maxSamplePerPath๋ฅผ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ, ๊ฐ„๊ฒฉ์„ ์กฐ๊ธˆ ๋Š˜๋ ค ์  ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์œผ๋กœ ์ตœ์ข… step์ด ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค.

๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์  ์ฐ๊ธฐ : ์ด์ œ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ, ๊ฒฝ๋กœ๋ฅผ ์‹œ์ž‘๋ถ€ํ„ฐ ๋๊นŒ์ง€ step ๊ฐ„๊ฒฉ์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๋ฉด์„œ ์ขŒํ‘œ๋ฅผ ์ƒ˜ํ”Œ๋งํ•ฉ๋‹ˆ๋‹ค. len์— step์„ ๋”ํ•ด๊ฐ€๋ฉด์„œ ๋ฃจํ”„๊ฐ€ ์ง„ํ–‰๋˜๋ฉฐ, pathEl.getPointAtLength(len)๋ฅผ ํ†ตํ•ด len ๊ฑฐ๋ฆฌ๋งŒํผ ๋–จ์–ด์ง„ ์ง€์ ์˜ ์ขŒํ‘œ๋ฅผ ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ , isFirst๊ฐ€ true์ผ์‹œ, pen์„ 0, ์•„๋‹ ์‹œ pen์„ 1๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ localPoints์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.์ดํ›„ isFirst๋ฅผ false๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค(์ด๋กœ์จ, path ์ฒซ ์  ์ดํ›„๋Š” ๋ชจ๋‘ pen 1๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.)

๋˜ํ•œ, ๋ฃจํ”„ ์ข…๋ฃŒ ํ›„, ๋ณ„๋„๋กœ pathEl.getPointAtLength(totalLength)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฝ๋กœ์˜ ๋งˆ์ง€๋ง‰ ์ ์„ ์–ป๊ณ , ์ด๋ฅผ localPoints์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ž„์‹œ path ์ œ๊ฑฐ : ์‚ฌ์šฉ์ด ๋๋‚œ pathEl์€ ๋‹ค์‹œ tempSvg.removeChild(pathEl)๋กœ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ฒฝ๋กœ ๊ฒน์นจ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ณ , ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ ์ž…๋‹ˆ๋‹ค.

๋„ํ˜• ๊ฐ„ bridge ์ถ”๊ฐ€ : ํ•œ ๋„ํ˜•์˜ ์ ์„ points์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์—, ๋งŒ์•ฝ ์ด์ „ ๋„ํ˜•์˜ ๋งˆ์ง€๋ง‰ ์œ„์น˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ(lastGlobalPt๊ฐ€ null์ด ์•„๋‹Œ ๊ฒฝ์šฐ), ๊ทธ ์ ์—์„œ ํ˜„์žฌ ์ƒˆ ๊ฒฝ๋กœ์˜ ์ฒซ ์ ๊นŒ์ง€ ํŽœ์„ ๋“ค์–ด ์ด๋™ํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€๋กœ ์ƒ˜ํ”Œ๋งํ•ฉ๋‹ˆ๋‹ค. bridge ์ƒ˜ํ”Œ๋ง ๋ฐ€๋„๋Š” ๊ธฐ๋ณธ step์— opts.bridgeScale๋ฅผ ๊ณฑํ•ด ์กฐ์ ˆํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ : bridgeStep = step * bridgeScale bridge ๊ตฌ๊ฐ„์€ ํŽœ์„ ๋“  ์ด๋™์ด๋ฏ€๋กœ, pen์€ 0์œผ๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

์  ๋ˆ„์  ๋ฐ lastGlobalPt ๊ฐฑ์‹  : 29. ์ด์ œ ๋ธŒ๋ฆฌ์ง€ ์ (๋งŒ์•ฝ ์žˆ๋‹ค๋ฉด)์ด points์— ์ถ”๊ฐ€๋œ ์ƒํƒœ์—์„œ, ํ˜„์žฌ ๋„ํ˜•์˜ ์‹ค์ œ ๊ฒฝ๋กœ ์ ๋“ค(localPoints ๋ฐฐ์—ด)์„ ์ˆœ์„œ๋Œ€๋กœ points ๋ฐฐ์—ด์— ์ด์–ด๋ถ™์ž…๋‹ˆ๋‹ค. ์ดํ›„ lastGlobalPt๋ฅผ localPoints์˜ ๋งˆ์ง€๋ง‰ ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  prepared ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์œ„ ๊ณผ์ •์„ ๋งˆ์น˜๋ฉด, points ๋ฐฐ์—ด์—๋Š” SVG์˜ ๋ชจ๋“  ๋„ํ˜• ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์ƒ์„ฑ๋œ ์ ์ด ์ˆœ์„œ๋Œ€๋กœ ๋‹ด๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ tempSvg (์ž„์‹œ๋กœ ๋งŒ๋“ค์—ˆ๋˜ ๋ณด์กฐ SVG ์š”์†Œ)๋ฅผ document.body.removeChild(tempSvg)๋กœ ์ œ๊ฑฐํ•˜์—ฌ, ํ™”๋ฉด์— ๋ณด์ด์ง€ ์•Š๊ฒŒ ์ƒ์„ฑํ–ˆ๋˜ ์š”์†Œ๋ฅผ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  points ๋ฐฐ์—ด์„ returnํ•˜์—ฌ ํ•จ์ˆ˜ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.

์ถœ๋ ฅ ๊ฒฐ๊ณผ

์ด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’ points๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ javascript ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.

[
  { x: Number, y: Number, pen: Number },
  { x: Number, y: Number, pen: Number },
  ...
]

์ด ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด, ์ขŒํ‘œ -> ๋กœ๋ด‡์˜ step ์ฆ๋ถ„๊ฐ’ ์œผ๋กœ ๋ฐ”๊พธ๋Š” ์ฒ˜๋ฆฌ๋ฅผ ๊ฑฐ์ฒ˜, ๋กœ๋ด‡์ด ์ด์šฉ ๊ฐ€๋Šฅํ•œ ๋ช…๋ น์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

normalizeToBox(points)

normalizeToBox ํ•จ์ˆ˜๋Š” points์˜ ๋ชจ๋“  ์ ์„ 0 ~ SVG_BOX_SIZE ๋ฒ”์œ„์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ๊ทธ๋ฆผ์„ SVG_BOX_SIZE x SVG_BOX_SIZE ํฌ๊ธฐ์˜ ๋ฐ•์Šค์— ์ตœ๋Œ€ํ•œ ๊ฝ‰ ์ฐจ๊ฒŒ ์ถ•์†Œ/ํ™•๋Œ€ํ•˜๊ณ  ์œ„์น˜๋ฅผ ๋งž์ถฅ๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

์ตœ๋Œ€ ์ตœ์†Œ ๊ฐ’ ์ฐพ๊ธฐ : points์˜ ์ ์„ ๋ชจ๋‘ ์ˆœํšŒํ•˜๋ฉฐ minX, maxX, minY, maxY๋ฅผ ๊ตฌํ•ฉ๋‹ˆ๋‹ค. ์›๋ณธ ๊ฒฝ๋กœ์˜ ํญ๊ณผ ๋†’์ด ๊ณ„์‚ฐ : w = maxX - minX , h = maxY - minY์™€ ๊ฐ™์€ ์‹์œผ๋กœ ์›๋ณธ points์˜ ํญ๊ณผ ๋†’์ด๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. ์ •๊ทœํ™” ์Šค์ผ€์ผ ๊ณ„์‚ฐ : ๊ฒฝ๋กœ๊ฐ€ SVG_BOX_SIZE์— ๋“ค์–ด์˜ค๋„๋ก ๋” ํฐ ๊ธธ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์Šค์ผ€์ผ ๊ณ„์ˆ˜ s๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. s = SVG_BOX_SIZE / max(w, h) ์ค‘์•™ ์ •๋ ฌ์„ ์œ„ํ•œ ์˜คํ”„์…‹ ๊ณ„์‚ฐ : ์Šค์ผ€์ผ ์ ์šฉ ํ›„, ๋‚จ๋Š” ์—ฌ๋ฐฑ์„ ์–‘์ชฝ์— ๋™์ผํ•˜๊ฒŒ ๋ถ„๋ฐฐํ•˜๊ธฐ ์œ„ํ•ด ๊ฒฝ๋กœ๊ฐ€ ๋ฐ•์Šค์˜ ์ค‘์•™์— ์œ„์น˜ํ•˜๊ฒŒ ํ•˜๋Š” ์˜คํ”„์…‹์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

  const offX = (plotto.SVG_BOX_SIZE - newW) / 2;
  const offY = (plotto.SVG_BOX_SIZE - newH) / 2;

์ขŒํ‘œ ๋ณ€ํ™˜ : ๋ชจ๋“  ์ ์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ณ€ํ™˜์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์›์  ์ด๋™: (p.x - minX, p.y - minY), ์Šค์ผ€์ผ ์ ์šฉ : ๊ณฑํ•˜๊ธฐ s, ์˜คํ”„์…‹ ์ ์šฉ : + offX / offY ์ด๋•Œ, pen ์ƒํƒœ๋Š” ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ขŒํ‘œ ๋ณ€ํ™˜ ์ดํ›„, ์ถœ๋ ฅ์ขŒํ‘œ๋Š” ํ•ญ์ƒ 0 ~ SVG_BOX_SIZE ๋ฒ”์œ„ ๋‚ด์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค.

mapBoxToRobotTargets(points, k = 1.0, flipY = false)

์ •๊ทœํ™” ๋œ points ๊ธฐ์ค€(normalizeToBox๋ฅผ ๊ฑฐ์นœ points ๋ฐฐ์—ด ๊ธฐ์ค€) ๋กœ๋ด‡ ์ž‘์—… ์ขŒํ‘œ๊ณ„๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. SVG ๊ฒฝ๋กœ๋ฅผ ๋กœ๋ด‡ ํŽœ์ด ๋”ฐ๋ผ๊ฐˆ ์ ˆ๋Œ€ ์œ„์น˜ ์ขŒํ‘œ๋กœ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

๋กœ๋ด‡ ๊ธฐ์ค€์  ๊ณ„์‚ฐ : const home = plotto.fkPenXY_deg(0, 0);์œผ๋กœ joint1, joint2๊ฐ€ ๊ฐ๊ฐ 0๋„์ผ ๋•Œ, ํŽœ ๋ ์œ„์น˜๋ฅผ home์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋ชจ๋“  SVG ์ขŒํ‘œ๋Š” ์ด ๊ธฐ์ค€์ ์— ์ƒ๋Œ€์ ์œผ๋กœ ๋ฐฐ์น˜๋ฉ๋‹ˆ๋‹ค.

SVG ์ขŒํ‘œ ์ถ”์ถœ ๋ฐ ๋ฐ˜์ „ ์ฒ˜๋ฆฌ : filpY === true์ผ ๊ฒฝ์šฐ ๋กœ๋ด‡ ์ขŒํ‘œ๊ณ„ ์ฐจ์ด๋ฅผ ๋ณด์ •ํ•˜๊ธฐ ์œ„ํ•ด y์ถ•์„ ๋ฐ˜์ „ํ•˜๋ฉฐ, u = p.x, v = p.y๋กœ ์ขŒํ‘œ๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

๋กœ๋ด‡ ์ขŒํ‘œ๊ณ„๋กœ ๋ณ€ํ™˜ : ์ •๊ทœํ™”๋œ ๋ฐ•์Šค ์ขŒํ‘œ์— ์Šค์ผ€์ผ ๋ณ€์ˆ˜ k(ํ‰์†Œ์—๋Š” 1)๋ฅผ ์ ์šฉํ•œ ๋’ค, ๊ธฐ์ค€์  home์„ ๋”ํ•˜์—ฌ ์‹ค์ œ ๋กœ๋ด‡ ์ขŒํ‘œ๊ณ„๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, pen์˜ ์ƒํƒœ๋Š” ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

x = home.x + u * k
y = home.y + v * k

์ดํ›„ ๋ณ€ํ™˜๋œ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

resamplePathByAngle(points, maxDeltaDeg = plotto.MAX_DELTA_DEG)

resamplePathByAngle ํ•จ์ˆ˜๋Š” ์—ฐ์†๋œ ๋‘ ์  ์‚ฌ์ด์˜ ๊ด€์ ˆ ๊ฐ๋„ ๋ณ€ํ™”๊ฐ€ maxDeltaDeg๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ์ค‘๊ฐ„ ์ ์„ ์‚ฝ์ž…ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์‹คํ–‰ ๋™์ž‘

์ดˆ๊ธฐํ™” ๋ฐ ์ฒซ ์  ์ถ”๊ฐ€ : ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ result๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ฒซ ์ ์€ ๊ทธ๋Œ€๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ฒซ ์ ์˜ ์—ญ๊ธฐ๊ตฌํ•™ ํ•ด๋„ ๋ฏธ๋ฆฌ ๋ณด๊ด€ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๊ฐ ์ธ์ ‘ํ•œ ์  ์Œ(prevPoint, currPoint)์— ๋Œ€ํ•ด ๋‘ ์ ์˜ ์—ญ๊ธฐ๊ตฌํ•™ ๊ฒฐ๊ณผ ๊ฐ๋„๋ฅผ ๊ตฌํ•œ ๋’ค, ๊ฐ๊ฐ ๋ณ€ํ™”๋Ÿ‰์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์  ์‚ฝ์ž… : ๋‘ ๊ด€์ ˆ์˜ ๊ฐ๋„ ๋ณ€ํ™”๊ฐ€ maxDeltaDeg ์ดํ•˜๋ผ๋ฉด ๊ทธ๋Œ€๋กœ ๋‘๊ณ , ์•„๋‹ˆ๋ผ๋ฉด ์ค‘๊ฐ„๊ฐ’mid์„ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์ ์˜ pen ์ƒํƒœ๋Š” ํ˜„์žฌ ์„ธ๊ทธ๋จผํŠธ์˜ ๋ ์ ๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

mid์— ๋Œ€ํ•ด IK๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , prevPoint -> mid์™€ mid -> currPoint์— ๋Œ€ํ•ด ๋‘ ๊ตฌ๊ฐ„์— ์žฌ๊ท€์ ์œผ๋กœ ๊ฐ™์€ ๊ณผ์ •์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์žฌ๊ท€๋ฅผ ํ†ตํ•ด ๋ถ„ํ• ์ด ์™„๋ฃŒ๋˜๋ฉด PrevPoint์—์„œ currPoint์— ์ด๋ฅด๋Š” ์ž‘์€ ์„ธ๊ทธ๋จผํŠธ ์ ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ฐ ์„ธ๊ทธ๋จผํŠธ์˜ ์ ์„ result์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ข…์ ์œผ๋กœ result๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.


2.5. ์›€์ง์ž„ ๋ช…๋ น ์••์ถ• ๋ฐ ์ธ์ฝ”๋”ฉ: plotEncode / plotDecode

์ž‘๋™ ํ๋ฆ„

  1. encodeNibble(d) / decodeNibble(n)

    • ์ƒ์„ฑ๋œ motionJson์„ ํ•˜๋“œ์›จ์–ด๋กœ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด ์ด์ง„ ๋ฐ์ดํ„ฐ๋กœ ์••์ถ•ํ•ฉ๋‹ˆ๋‹ค.

    • Plotto ์ฝ”๋“œ์—์„œ๋Š” ๋‘ ๊ด€์ ˆ์˜ ๋ณ€ํ™”๋Ÿ‰, ์ฆ‰ ฮ” ๋ช…๋ น๋“ค๊ณผ ํŽœ ์—…/๋‹ค์šด ๋ช…๋ น์„ ํšจ์œจ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ปค์Šคํ…€ ์ธ์ฝ”๋”ฉ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    • ์ด๋•Œ ํŠน์ˆ˜ ๋ฐ”์ดํŠธ ๊ฐ’์„ ํ†ตํ•ด ํƒ€ ๋ช…๋ น๋“ค๊ณผ ๊ตฌ๋ถ„ํ•˜๋ฉด์„œ๋„, ๋‹จ 1byte ๋งŒ์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ž์„ธํ•œ ๋‚ด์šฉ์€ Plotto Path ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.)

    ์ฐธ๊ณ  : ๋งคํ•‘ ํ…Œ์ด๋ธ”
    $\mathbf{d}$ ๊ฐ’ (10์ง„์ˆ˜) 4๋น„ํŠธ ์ด์ง„์ˆ˜ (Nibble) $\mathbf{d}$ ๊ฐ’ (10์ง„์ˆ˜) 4๋น„ํŠธ ์ด์ง„์ˆ˜ (Nibble)
    $\mathbf{-7}$ $0b1001$ $\mathbf{0}$ $0b0000$
    $\mathbf{-6}$ $0b1010$ $\mathbf{1}$ $0b0001$
    $\mathbf{-5}$ $0b1011$ $\mathbf{2}$ $0b0010$
    $\mathbf{-4}$ $0b1100$ $\mathbf{3}$ $0b0011$
    $\mathbf{-3}$ $0b1101$ $\mathbf{4}$ $0b0100$
    $\mathbf{-2}$ $0b1110$ $\mathbf{5}$ $0b0101$
    $\mathbf{-1}$ $0b1111$ $\mathbf{6}$ $0b0110$
    $\mathbf{7}$ $0b0111$
    • Plotto_Path์˜ ๋ณ€ํ™˜๊ทœ์น™์— ์˜ํ•ด, 0b1000์— ๋Œ€ํ•œ ์—”ํŠธ๋ฆฌ๊ฐ€ ์—†๋‹ค๋Š” ์ ์„ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. encodeNibble์—์„œ ์•„์˜ˆ ์ƒ์„ฑํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ decodeNibble์—์„œ๋„ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • encodeNibble(d) : -7 ~ 7 ๋ฒ”์œ„์˜ ์ •์ˆ˜๋ฅผ 4๋น„ํŠธ ๊ฐ’(0x0~0xF)์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
    • decodeNibble(n) : 4๋น„ํŠธ ๊ฐ’์„ ๋‹ค์‹œ -7~7 ์ •์ˆ˜๋กœ ๋ณต์›ํ•˜๋Š” ๋งคํ•‘์ž…๋‹ˆ๋‹ค.
  2. encodeDeltaByte(d1,d2) / decodeDeltaByte(byte)

    • encodeDeltaByte(d1,d2)

      • ๋‚ด๋ถ€์ ์œผ๋กœ encodeNibble์„ ์ด์šฉํ•˜์—ฌ ์ƒ์œ„ 4๋น„ํŠธ๋Š” d1์„, ํ•˜์œ„ 4๋น„ํŠธ๋Š” d2๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.
      • ๋‘ ๊ด€์ ˆ์˜ ฮ”์Šคํ…(d1, d2, ๊ฐ๊ฐ -7~7 ๋ฒ”์œ„)์„ ๋ฐ›์•„ ํ•˜๋‚˜์˜ ๋ฐ”์ดํŠธ ๊ฐ’์œผ๋กœ ํ•ฉ์นฉ๋‹ˆ๋‹ค.
      • ์˜ˆ: d1=3, d2=-1์ด๋ผ๋ฉด
        encodeNibble(3)=0b0011, encodeNibble(-1)=0b1111์ด๋ฏ€๋กœ
        ์ตœ์ข… ๊ฐ’์€ 0b00111111 (0x3F)์ด ๋ฉ๋‹ˆ๋‹ค.
    • decodeDeltaByte(byte)

      • 4๋น„ํŠธ ๊ฐ’์„ ๋‹ค์‹œ -7~7 ์ •์ˆ˜๋กœ ๋ณต์›ํ•˜๋Š” ๋งคํ•‘์ž…๋‹ˆ๋‹ค.
      • ๋ฐ”์ดํŠธ๋ฅผ ๋ฐ›์•„ ์ƒ์œ„/ํ•˜์œ„ 4๋น„ํŠธ๋ฅผ ๊ฐ๊ฐ ์ถ”์ถœํ•˜๊ณ , decodeNibble์„ ํ†ตํ•ด
        ์ •์ˆ˜ ๊ฐ’์œผ๋กœ ํ’€์–ด๋‚ธ ํ›„ { d1: ..., d2: ... } ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    ์ด ๋‘ ํ•จ์ˆ˜๋Š” ๊ด€์ ˆ ๋ฐ ํŽœ ๋ช…๋ น์„ ์••์ถ•/ํ•ด์ œํ•˜๋Š” ๊ธฐ๋ณธ ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค.

  3. plotEncode(motionJson)

    • motionJson ๋ฐฐ์—ด์„ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„, ๊ฐ ๋ช…๋ น์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ํŠน์ˆ˜ํ•˜๊ฒŒ ์ธ์ฝ”๋”ฉ๋œ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

      ์ฝ”๋“œ ๋ณด๊ธฐ
      function plotEncode(motionJson) {
        const out = [];
        let prevPen = 0;
        for (let i = 0; i < motionJson.length; i++) {
            const cmd = motionJson[i];
            const pen = cmd.pen ? 1 : 0;
            if (pen !== prevPen) {
                out.push(pen === 1 ? 0x80 : 0x08);
                prevPen = pen;
            }
            out.push(encodeDeltaByte(cmd.d1, cmd.d2));
        }
        return out;
      }

    ๋™์ž‘๋ฐฉ์‹

    1. ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ๋นˆ ๋ฐฐ์—ด out์„ ์ƒ์„ฑํ•˜๊ณ , ์ด์ „ ํŽœ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” prevPen์„ 0(pen up)์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

    2. motionJson ๋ฐฐ์—ด์˜ ๊ฐ ๋ช…๋ น cmd๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆœํšŒํ•ฉ๋‹ˆ๋‹ค.

    3. ํ˜„์žฌ ๋ช…๋ น์˜ ํŽœ ์ƒํƒœ๋ฅผ ์ˆซ์ž ๊ฐ’์œผ๋กœ ์ •๊ทœํ™”ํ•ฉ๋‹ˆ๋‹ค.

      • pen = cmd.pen ? 1 : 0
    4. ํ˜„์žฌ ํŽœ ์ƒํƒœ(pen)์™€ ์ด์ „ ํŽœ ์ƒํƒœ(prevPen)๋ฅผ ๋น„๊ตํ•˜์—ฌ ํŽœ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

      4-1. ํŽœ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด, ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค์Œ ๋ช…๋ น ๋ฐ”์ดํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

      • pen up โ†’ pen down : 0x80
      • pen down โ†’ pen up : 0x08
    5. ํŽœ ์ƒํƒœ ๋ณ€๊ฒฝ ๋ช…๋ น์„ ๊ธฐ๋กํ•œ ํ›„, prevPen์„ ํ˜„์žฌ ํŽœ ์ƒํƒœ๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

    6. ๋‘ ๊ด€์ ˆ์˜ ฮ” ์ด๋™๋Ÿ‰ (d1, d2)๋ฅผ encodeDeltaByte(d1, d2)๋ฅผ ํ†ตํ•ด ํ•˜๋‚˜์˜ ๋ฐ”์ดํŠธ๋กœ ์ธ์ฝ”๋”ฉํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ out ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

    7. ์ด ฮ” ์ด๋™ ๋ฐ”์ดํŠธ๋Š” ์‹ค์ œ ์ด๋™์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ํ•ญ์ƒ ์ถ”๊ฐ€๋˜๋ฉฐ, (d1, d2) = (0, 0)์ผ ๊ฒฝ์šฐ 0x00์ด ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.

    8. ๋ชจ๋“  ๋ช…๋ น์„ ์ฒ˜๋ฆฌํ•˜๋ฉด, out ๋ฐฐ์—ด์—๋Š” ํŽœ ์ƒํƒœ ๋ณ€ํ™”์™€ ๊ด€์ ˆ ์ด๋™์ด ์ˆœ์„œ๋Œ€๋กœ ๊ธฐ๋ก๋œ ๋ฐ”์ดํŠธ ์‹œํ€€์Šค๊ฐ€ ์™„์„ฑ๋ฉ๋‹ˆ๋‹ค.

    9. ์™„์„ฑ๋œ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด out์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. plotDecode(byteArray)

    • plotDecode๋Š” plotEncode์˜ ์—ญ์œผ๋กœ, ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์„ ๋ฐ›์•„ ๋‹ค์‹œ {d1,d2,pen} ๋ช…๋ น ๊ฐ์ฒด ๋ฆฌ์ŠคํŠธ๋กœ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.
    • ์ฃผ๋กœ ๋””๋ฒ„๊น…์ด๋‚˜ ๊ฒ€์ฆ ์šฉ๋„๋กœ ์“ฐ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ์ฝ”๋“œ ๋ณด๊ธฐ
    function plotDecode(byteArray) {
    if (!Array.isArray(byteArray)) {
        throw new Error("plotDecode: byteArray must be an array");
    }
    
    const out = [];
    let pen = 0; 
    
    for (let i = 0; i < byteArray.length; i++) {
        const b = byteArray[i];
    
        if (b === 0x80) {
            pen = 1;
        } else if (b === 0x08) {
            pen = 0;
        } else {
            const { d1, d2 } = decodeDeltaByte(b);
            out.push({ d1, d2, pen });
        }
    }
    
    return out;
    }

    ๋™์ž‘๋ฐฉ์‹

    1. ์ž…๋ ฅ ๊ฒ€์ฆ

      • byteArray๊ฐ€ ๋ฐฐ์—ด์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
    2. ์ดˆ๊ธฐํ™”

      • out: ๊ฒฐ๊ณผ ๊ฐ์ฒด ๋ฐฐ์—ด
      • pen: ํŽœ ์ƒํƒœ ์ดˆ๊ธฐํ™” (0: ํŽœ ์—…, 1: ํŽœ ๋‹ค์šด)
    3. ๋ฐฐ์—ด ์ˆœํšŒ

      • byteArray์˜ ๊ฐ ๋ฐ”์ดํŠธ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    4. ํŽœ ์ƒํƒœ ์ฒ˜๋ฆฌ

      • 0x80: ํŽœ ๋‹ค์šด (pen = 1)
      • 0x08: ํŽœ ์—… (pen = 0)
    5. ฮ” ์ด๋™ ๋ช…๋ น ์ฒ˜๋ฆฌ

      • 0x80 ๋˜๋Š” 0x08 ์™ธ์˜ ๋ฐ”์ดํŠธ๋Š” ฮ” ์ด๋™ ๋ช…๋ น์ž…๋‹ˆ๋‹ค.
      • decodeDeltaByte๋ฅผ ์‚ฌ์šฉํ•ด (d1, d2) ๊ฐ’์„ ๋ณต์›ํ•˜๊ณ , ํ˜„์žฌ pen ์ƒํƒœ์™€ ํ•จ๊ป˜ <>{d1, d2, pen} ๊ฐ์ฒด๋ฅผ out ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    6. ํŽœ ์ƒํƒœ๋งŒ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ

      • 0x00์€ d1 = 0, d2 = 0, ํ˜„์žฌ ํŽœ ์ƒํƒœ๋กœ ๋ณต์›๋ฉ๋‹ˆ๋‹ค.
      • ์ด ๊ฒฝ์šฐ ์ œ์ž๋ฆฌ ์ด๋™ ๋ช…๋ น์œผ๋กœ ํ•ด์„๋ฉ๋‹ˆ๋‹ค.
    7. ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜

      • ์ตœ์ข…์ ์œผ๋กœ {d1, d2, pen} ๊ฐ์ฒด๋“ค์˜ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

Plotto ์ฝ”๋“œ๋Š” 2-DOF ํŽœ ๋กœ๋ด‡ ํŒ”์„ ์œ„ํ•œ ๊ฒฝ๋กœ ์ƒ์„ฑ ๋ฐ ์ œ์–ด ๋ช…๋ น ์ƒ์„ฑ๊ธฐ์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๋Š” SVG ํ˜•ํƒœ๋กœ ๊ทธ๋ฆฌ๋ ค๋Š” ํ˜•์ƒ์„ ์ž…๋ ฅํ•˜๊ณ , ์ฝ”๋“œ๋Š” ์ด๋ฅผ ๋กœ๋ด‡ ํŒ”์˜ ์ž‘์—… ์˜์—ญ์— ๋งž๊ฒŒ ์Šค์ผ€์ผ๋ง ๋ฐ ๋ณ€ํ™˜ํ•˜์—ฌ ์—ฐ์†๋œ ํŽœ ์›€์ง์ž„ ์ขŒํ‘œ ๋ชฉ๋ก์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์ดํ›„ ๋กœ๋ด‡ ํŒ”์ด ์›ํ™œํ•˜๊ฒŒ ์›€์ง์ผ ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋‹น ๊ฒฝ๋กœ๋ฅผ ์„ธ๋ถ„ํ™”ํ•˜๊ณ , ๊ฐ ๊ตฌ๊ฐ„์— ๋Œ€ํ•œ ๊ด€์ ˆ์˜ ์„ธ๋ถ€ ์Šคํ… ๋ช…๋ น์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ์ด ๋ช…๋ น๋“ค์„ ํšจ์œจ์ ์ธ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ, ์‹ค์ œ ์ œ์–ด ํ•˜๋“œ์›จ์–ด๋กœ ์‰ฝ๊ฒŒ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค:

โ€ข ๊ธฐ๊ตฌํ•™ ๊ณ„์‚ฐ (FK & IK): ๋กœ๋ด‡ ํŒ”์˜ ์ขŒํ‘œ โ†” ๊ด€์ ˆ ๊ฐ๋„ ๋ณ€ํ™˜์„ ๋‹ด๋‹นํ•˜์—ฌ ๊ฒฝ๋กœ ์ ์„ ๊ด€์ ˆ ๋ช…๋ น์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

โ€ข SVG ๊ฒฝ๋กœ ์ฒ˜๋ฆฌ: ๋ณต์žกํ•œ SVG ๋„ํ˜•๋„ ์ผ๋ จ์˜ ์ง์„  ์ ๋“ค๋กœ ๋ถ„ํ•ดํ•˜์—ฌ ๋”ฐ๋ผ๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

โ€ข ๊ฒฝ๋กœ ์ตœ์ ํ™” (resample): ๊ด€์ ˆ์˜ ๋ฌผ๋ฆฌ์  ์ œ์•ฝ์„ ๊ณ ๋ คํ•ด ๊ฒฝ๋กœ๋ฅผ ๋ถ€๋“œ๋Ÿฝ๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ค๋“ฌ์Šต๋‹ˆ๋‹ค.

โ€ข ๋ชจ์…˜ JSON ์ƒ์„ฑ: ์‹œ์ž‘๋ถ€ํ„ฐ ๋๊นŒ์ง€ ํŽœ์˜ ์›€์ง์ž„๊ณผ ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๊ธฐ ๋™์ž‘์„ ๋ชจ๋‘ ํฌํ•จํ•œ ์Šคํ… ๋ช…๋ น ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

โ€ข ๋ช…๋ น ์ธ์ฝ”๋”ฉ: ์ด ์Šคํ… ๋ช…๋ น ๋ฆฌ์ŠคํŠธ๋ฅผ ์ตœ์†Œํ•œ์˜ ๋ฐ์ดํ„ฐ๋กœ ํ‘œํ˜„ํ•ด ์ „์†กํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ธ์ˆ˜์ธ๊ณ„๋ฐ›๋Š” ๊ฐœ๋ฐœ์ž๋Š” ์œ„ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ,

  • ๋กœ๋ด‡ ํŒ”์˜ ๋ฌผ๋ฆฌ์  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์กฐ์ •ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋กœ๋ด‡์— ์ ์šฉํ•  ๊ฒฝ์šฐ configure() ๋ถ€๋ถ„๊ณผ kinematics ๋ถ€๋ถ„์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๊ณ ,
  • SVG ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋กœ๋ด‡ ์›€์ง์ž„์„ ์ƒ์„ฑํ•˜๋Š” ๋กœ์ง์„ ์ดํ•ดํ•˜์—ฌ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์„ธ๋ถ„ํ™” ๋‹จ๊ณ„(MAX_DELTA_DEG ๋“ฑ)๋‚˜ ์ƒ˜ํ”Œ๋ง ๋ฐ€๋„(samplesPerPath ๋“ฑ)๋ฅผ ํŠœ๋‹ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ motionJson๊ณผ plot ๊ฒฐ๊ณผ๋ฅผ ์ด์šฉํ•ด ์‹ค์ œ ํ•˜๋“œ์›จ์–ด ์ œ์–ด ์ฝ”๋“œ์™€ ์—ฐ๋™ํ•˜๊ฑฐ๋‚˜, ์‹œ๋ฎฌ๋ ˆ์ด์…˜์—์„œ ์›€์ง์ž„์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ธ

Image

Clone this wiki locally