Ang Matematika at ActionScript ng Kurba: Mga Gradient at Normal
Tagalog (Wikang Tagalog) translation by Anna Nelson (you can also view the original English article)
Tinalakay na natin ang pagguhit ng mga kurba, at ang pagtuklas ng kanilang parisukat at kubikong mga ugat, pati na rin ang nakahandang mga aplikasyon para sa paggamit ng mga parisukat na mga ugat sa loob ng mga laro. Ngayon, katulad ng pangako ko, titingnan natin ang mga aplikasyon para sa pagtuklas ng mga kubikong ugat, pati na rin ang mga gradient at normal ng kurba, katulad ng pagpapatalbog ng mga bagay mula sa mga kurbang pang-ibabaw. Halika na!
Halimbawa
Tingnan natin ang isang praktikal na gamit ng matematikang ito:
Sa demong ito, ang “barko” ay tumatalbog sa mga kanto ng SWF at ang kurba. Ang dilaw na tuldok ang kumakatawan sa pinakamalapit na punto papunta sa barko na nasa kurba. Maaari ninyong ayusin ang hugis ng kurba sa pamamagitan ng paghila sa mga pulang tuldok, at ayusin ang paggalaw ng barko gamit ang mga arrow key.
Hakbang 1: Pinakamaikling Distansya sa Kurba
Isaalang-alang natin ang senaryo kung saan ang punto ay nakalagay malapit sa parisukat na kurba. Paano ninyo kakalkulahin ang pinakamaikling distansya sa pagitan ng punto at kurba?

Buweno, magsimula tayo sa Pythagoras's Theorem.
\[
Let\the\point\be\ (x_p,\ y_p)\\
and\call\the\closest\point\on\the\curve\ (x_c,\ y_c)\\
Pagkatapos :\\
z^2 = x^2 + y^2\\
z^2 = (x_c-x_p)^2 + (y_c-y_p)^2\\
Nakatakda y_c=ax_c^2 + bx_c + c,\\
z^2 = (x_c-x_p)^2 + [(ax_c^2 + bx_c + c) -y_p]^2
\]
Makikita ninyo na pinalitan natin ang \(y_c\) ng parisukat na equation. Sa sulyap, makikita natin na ang pinakamataas na power ay 4. Kaya, mayroon tayong quartic na equation. Ang kailangan lang nating gawin ay hanapin ang pinakamaliit nap unto sa equation na ito upang magbigay sa atin ng pinakamaikling distansya mula sa punta hanggang sa parisukat na kurba.
Ngunit bago iyan, kailangan muna nating maunawaan ang mga gradient sa kurba…
Hakbang 2: Gradient ng Kurba
Bago tayo tumingin sa problema sa pagpapaliit ng quartic na equation, subukan muna nating unawain ang mga gradient ng kurba. Ang tuwid na linya ay mayroon lamang isang gradient. Ngunit ang gradient ng parisukat na kurba ay depende kung saang punto sa kurba ang tinutukoy natin. Tingnan ang Flash presentation sa ibaba:
Hilahin ang mga pulang tuldok sa paligid upang baguhin ang parisukat na kurba. Maaari niyo ding paglaruan ang hawakan ng slider upang baguhin ang posisyon ng asul na tuldok sa tabi ng x. Habang nagbabago ang asul na tuldok, magbabago rin ang gradient na iginuhit.
Hakbang 3: Gradient Sa Pamamagitan ng Calculus
Dito kung saan magiging kapaki-pakinabang ang calculus. Maaaring nahulaan ninyo na ang pagdidifferentiate ng parisukat na equation ay magbibigay sa inyo ng gradient ng kurba.
\[
f(x) = ax^2+bx+c\\
\frac{df(x)}{dx} = 2ax+b
\]
Kaya ang \(\frac{df(x)}{dx}\) ang gradient ng
parisukat ng kurba, at ito ay nakadepende sa \(x\) na coordinate. Buweno, mabuting
bagay na mayroon tayong paraan upang pakitunguhan ito: diff1(x:Number)
ay magbabalik ng
halaga pagkatapos ng isang differentiation.
Upang maiguhit ang gradient, kakailanganin natin ng equation na kakatawan sa linya, \(y=mx+c\). Ang coordinate ng asul na punto \((x_p, y_p)\) ay papalitan upang maging \(x\) at \(y\). At ang gradient ng linya na nakita sa pamamagitan ng differentiation ay mapupunta sa \(m\). Kung gayon, ang y-intercept ng linya, \(c\) ay maaaring makalkula sa pamamagitan ng ilang trabaho sa algebra.
Tingnan ang AS3:
var x:Number = s.value var y:Number = quadratic_equation.fx_of(s.value) point.x = x; point.y = y; /** * y = mx + c; * c = y - mx; <== use this to find c */ var m:Number = quadratic_equation.diff1(x); var c:Number = y - m * x; graphics.clear(); graphics.lineStyle(1, 0xff0000); graphics.moveTo(0, c); graphics.lineTo(stage.stageWidth, m * stage.stageWidth + c);
Hakbang 4: Mga Coordinate System
Palaging isaisip ang binaligtad na y-axis ng Flash coordinate space katulad ng ipinapakitang larawan sa ibaba. Sa unang sulyap, ang diagram sa kanan ay maaaring mukhang negatibong gradient – ngunit dahil sa binaligtad na y-axis, ito ay talagang positibong gradient.

Ganoon din para sa pinakamaliit nap unto katulad ng ipinapakita sa ibaba. Dahil sa binaligtad na y-axis, ang pinakamaliit nap unto sa Cartesian coordinate space (at (0,0)) ay katulad ng sa pinakamataas sa Flash coordinate space. Ngunit sa pamamagitan ng pagtukoy sa lokasyon ng pinagmulan sa Flash coordinate space kaugnay sa parisukat na kurba, ito talaga ang pinakamababang punto.



Hakbang 5: Tulin ng Pagbabago para sa Gradient
Ngayon sabihin na nating interesado akong malaman ang pinakamababang punto sa kurba – paano ako magpapatuloy? Tingnan ang larawan sa ibaba (ang parehong larawan ay nasa parehong coordinate space).



Upang makuha ang pinakamaliit na punto, i-e-equate lamang natin ang \(\frac{df(x)}{dx} = 0\), dahil sa depinisyon hinahanap natin ang punto kung saan ang gradient ay zero. Ngunit katulad ng ipinapakita sa itaas, lumalabas na ang pinakamataas nap unto sa kurba ay tumutugma din sa kondisyon. Kaya paano natin makikita ang kaibhan sa pagitan ng dalawang kaso na ito?
Subukan nating ang differentiation sa ikalawang antas. Ito ang magbibigay sa atin ng tulin ng pagbabago ng gradient.
\[
\frac{df(x)}{dx} = 2ax+b\\
\frac{df^2(x)}{dx^2} = 2a
\]
Ipapaliwanag ko kaugnay ng larawan sa ibaba (iginuhit sa Cartesian coordinate space). Makikita natin na habang nagdadagdag tayo sa x-axis, nagbabago ang gradient mula negatibo papuntang positibo. Kaya ang tulin ng pagbabago dapat ay positibo ang halaga.
Makikita din natin na kapag positibo ang \(\frac{df^2(x)}{dx^2}\), mayroong pinakamaliit na punto sa kurba. Kasalungat nito na kapag negatibo ang tulin, mayroong pinakamataas na punto.



Hakbang 6: Balik sa Problema
Ngayon handa na tayong lutasin ang problemang ipinakita sa Hakbang 1. Alalahanin ang parisukat na equation (kung saan ang pinakamataas na antas ay 4) na nakuha natin ang:
\[
z^2 = (x_c-x_p)^2 + [(ax_c^2 + bx_c + c) -y_p]^2
\]



Ang parehong quartic equation, naka-plot
Tandaan, interesado tayong makita ang pinakamaliit nap unto sa kurba na ito, dahil ang katumbas na punto sa orihinal na parisukat na kurba ay ang magiging punto na nasa pinakamaliit na distansya mula sa pulang tuldok.

Kaya, i-differentiate natin ang quartic na function upang makuhaa ang gradient ng kurba na ito, at pagkatapos i-equate ang gradient ng quartic function na ito sa zero. Makikita ninyo na ang gradient ay kubikong function talaga. You will see that the gradient is actually a cubic function. Irerekomenda ko ang mga interesadong mambabasa sa pahina ni Wolfram; para sa tutoryan na ito, hihilahin ko lamang ang resulta ng kanilang mga trabahong algebra:
\[
\frac{d(z^2)}{dx}=
2(x_c-x_p) + 2(ax_c^2 + bx_c + c - y_p)(2ax_c+b)\\
\frac{d(z^2)}{dx}= 2a^2(x_c)^3+3ab(x_c)^2+(b^2+2ac-2ay_p+1)(x_c)+(bc-by_p-x_p)\\
Equate\gradient\to 0\\
\frac{d(z^2)}{dx}=0\\
2a^2(x_c)^3+3ab(x_c)^2+(b^2+2ac-2ay_p+1)(x_c)+(bc-by_p-x_p)=0\\
Compare\with\cubic\ equation\\
Ax^3+Bx^2+Cx+D=0\\
A = 2a^2\\
B=3ab\\
C=b^2+2ac-2ay_p+1\\
D=bc-by_p-x_p
\]
Kwentahin ang mga ugat nitong (medyo magulo) kubikong function at makukuha natin ang mga coordinate ng tatlong asul na puntos katulad ng itinuturo sa ibaba.
Sunod, paano natin sinasala ang ating mga resulta para sa pinakamaliit na punto? Alalahanin mula sa nakaraang hakbang na ang pinakamaliit na punta ay may tulin ng pagbabago na positibo. Upang makuha ang tulan ng pagbabagong ito, i-differentiate ang kubikong function na kumakatawan sa gradient. Kapag ang tulin ng pagbabago para sa ibinigay na asul nap unto ay positibo, isa ito sa mga pinakamaliliit na puntos. Upang makuha ang pinakamaliit na punto, kung alin dito tayo interesado, piliin ang punto na may pinakamataas na tulin ng pagbabago.
Hakbang 7: Halimbawa ng Output
Kaya heto ang halimbawa ng pagsasakatuparan ng ideya na ipinaliwanag sa itaas. Maaari ninyong hilahin ang mga pulang tuldok sa paliging upang i-custimise ang inyong parisukat na kurba. Ang asul na tuldok ay maaari ding hilahin. Habang inililipat ninyo ang asul na tuldok, ang dilaw na tuldok ay malilipat din upang ang distansya sa pagitan ng asul at dilaw na tuldok ay maging pinakamaliiit sa lahat ng mga puntos sa kurba.
Habang nakikipag-ugnayan kayo sa Flash na presentasyon, maaaring may mga pagkakataon kung saan ang mga dilaw na tuldok ay lilitaw lahat nang sabay-sabay. Dalawa dito, lumabo na, ay kumakatawan sa mga ugat na nakuha mula sa kalkulasyon ngunit hindi tinanggap dahil hindi ang mga ito ang pinakamalalapit na mga puntos sa kurba sa asul na tuldok.
Hakbang 8: Pagsasakatuparan ng ActionScript
Kaya heto ang pagsasakatuparan ng ActionScript
ng nasa itaas. Makikita ninyo ang buong script sa Demo2.as.
Una sa lahat, kakailanganin nating gumuhit
ng parisukat na kurba. Tandaan na ang matrix na m2
ay tutukuyin para sa higit
pang kalkulasyon.
private function redraw_quadratic_curve():void { var cmd:Vector.<int> = new Vector.<int>; var coord:Vector.<Number> = new Vector.<Number>; //redraw curve; m1 = new Matrix3d( curve_points[0].x * curve_points[0].x, curve_points[0].x, 1, 0, curve_points[1].x * curve_points[1].x, curve_points[1].x, 1, 0, curve_points[2].x * curve_points[2].x, curve_points[2].x, 1, 0, 0,0,0,1 ); m2 = new Matrix3d( curve_points[0].y, 0, 0, 0, curve_points[1].y, 0, 0, 0, curve_points[2].y, 0, 0, 0, 0,0,0,1 ) m1.invert(); m2.append(m1); quadratic_equation.define(m2.n11, m2.n21, m2.n31); for (var i:int = 0; i < stage.stageWidth; i+=2) { if (i == 0) cmd.push(1); else cmd.push(2); coord.push(i, quadratic_equation.fx_of(i)); } graphics.clear(); graphics.lineStyle(1); graphics.drawPath(cmd, coord); }
At heto ang isa na nagsasakatuparan ng
matematikang konseptong ipinaliwanag. Ang c1
ay tumutukoy sa punto na walang
tiyak na posisyon sa entablado.
private function recalculate_distance():void { var a:Number = m2.n11; var b:Number = m2.n21; var c:Number = m2.n31; /*f(x) = Ax^3 + Bx^2 +Cx + D */ var A:Number = 2*a*a var B:Number = 3*b*a var C:Number = b*b + 2*c*a - 2*a*c1.y +1 var D:Number = c * b - b * c1.y - c1.x quartic_gradient = new EqCubic(); quartic_gradient.define(A, B, C, D); quartic_gradient.calcRoots(); roots = quartic_gradient.roots_R; var chosen:Number = roots[0]; if (!isNaN(roots[1]) && !isNaN(roots[2])) { //calculate gradient and rate of gradient of all real roots var quartic_rate:Vector.<Number> = new Vector.<Number>; for (var i:int = 0; i < roots.length; i++) { if (!isNaN(roots[i])) quartic_rate.push(quartic_gradient.diff1(roots[i])); else roots.splice(i, 1); } //select the root that will produce the shortest distance for (var j:int = 1; j < roots.length; j++) { //the rate that corresponds with the root must be the highest positive value //because that will correspond with the minimum point if (quartic_rate[j] > quartic_rate[j - 1]) { chosen = roots[j]; } } //position the extra roots in demo position_extras(); } else { //remove the extra roots in demo kill_extras(); } intersec_points[0].x = chosen intersec_points[0].y = quadratic_equation.fx_of(chosen); }
Hakbang 9: Halimbawa: Pagtiktik ng Banggaan
Gamitin natin ang konseptong ito sa pagtiktik ng nagsanib sa pagitan ng bilog at kurba.
Ang ideya ay simple: Kapag ang distansya sa pagitan ng asul na tuldok at dilaw na tuldok ay mas maikli kaysa sa radius ng asul na tuldok, mayroon tayong banggaan. Tingnan ang demo sa ibaba. Ang mga bagay na interactive ay ang mga pulang tuldok (upang kontrolin ang kurba) ang ang asul na tuldok. Kapag ang asul na tuldok ang bumabangga sa kurba, lalabo ito ng kaunti.
Hakbang 10: Pagsasakatuparan ng ActionScript
Bweno, ang code ay medyo simple. Tingnan
ang buong pinanggalingan sa CollisionDetection.as
.
graphics.moveTo(intersec_points[0].x, intersec_points[0].y); graphics.lineTo(c1.x, c1.y); var distance:Number= Math2.Pythagoras( intersec_points[0].x, intersec_points[0].y, c1.x, c1.y) if (distance < c1.radius) c1.alpha = 0.5; else c1.alpha = 1.0; t.text = distance.toPrecision(3);
Hakbang 11: Pagtalbok mula sa Kurba
Kaya ngayon na alam na natin kung kalian nangyayari ang banggaan, subukan nating i-program ang ilang tugon sa banggaan. Paano ang pagtalbok mula sa labas? Tingnan ang Flash na presentasyon sa ibaba.
Makikita ninyo ang barko (hugis tatsulok), ay napapaligiran ng bilog (naaaninag na asul). Kapag ang bilog ay bumangga sa kurba, ang barko ay tatalbog mula sa labas.
Hakbang 12: Pagkontrol sa Barko
Narito ang ActionScript upang makontrol ang barko.
public function CollisionDetection2() { /** * Instantiation of ship & its blue-ish circular area */ ship = new Triangle(); addChild(ship); ship.x = Math.random() * stage.stageWidth; ship.y = stage.stageHeight * 0.8; c1 = new Circle(0x0000ff, 15); addChild(c1); c1.alpha = 0.2; /** * Ship's velocity */ velo = new Vector2D(0, -1); updateShip(); stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKey); stage.addEventListener(KeyboardEvent.KEY_UP, handleKey); stage.addEventListener(Event.EXIT_FRAME, handleEnterFrame); /** * The curve and the calculations */ quadratic_equation = new EqQuadratic(); curve_points = new Vector.<Circle>; populate(curve_points, 0xff0000, 3); intersec_points = new Vector.<Circle>; populate(intersec_points, 0xffff00, 3, false); redraw_quadratic_curve(); } private function handleKey(e:KeyboardEvent):void { if (e.type == "keyDown") { if (e.keyCode == Keyboard.UP) isUp = true; else if (e.keyCode == Keyboard.DOWN) isDown = true; if (e.keyCode == Keyboard.LEFT) isLeft = true; else if (e.keyCode == Keyboard.RIGHT) isRight = true; } if (e.type == "keyUp") { if (e.keyCode == Keyboard.UP) isUp = false; else if (e.keyCode == Keyboard.DOWN) isDown = false; if (e.keyCode == Keyboard.LEFT) isLeft = false; else if (e.keyCode == Keyboard.RIGHT) isRight = false; } } private function handleEnterFrame(e:Event):void { /** * Control the magnitude */ if (isUp) velo.setMagnitude(Math.min(velo.getMagnitude()+0.2, 3)); else if(isDown) velo.setMagnitude(Math.max(velo.getMagnitude()-0.2, 1)); /** * Control the direction */ if (isRight) velo.setAngle(velo.getAngle() + 0.03); else if (isLeft) velo.setAngle(velo.getAngle() - 0.03); recalculate_distance(); if (distance < c1.radius) bounce(); updateShip(); } /** * Update ship's position, orientation and it's area (the blue-ish circle) */ private function updateShip():void { ship.x += velo.x; ship.y += velo.y; ship.rotation = Math2.degreeOf(velo.getAngle()); c1.x = ship.x; c1.y = ship.y; if (ship.x > stage.stageWidth || ship.x < 0) velo.x *= -1; if (ship.y > stage.stageHeight || ship.y < 0) velo.y *= -1; }
Makikita niyo na ang mga kontrol ng teklado ay nag-a-update ng mga bandila upang ipahiwatig kung ang kaliwa, taas, baba, o kanan na teklado ay pinipindot. Ang mga bandilang ito ay huhulihin ng enterframe na tagapamahala ng pangyayari at iaupdate ang laki at direksyon ng barko.
Hakbang 13: Pagkalkula sa Repleksyon na Vector
Natalakay ko na ang vector na kalkulasyon ng repleksyon ng vector sa paskil na ito. Dito, tatalakayin ko kung paano kumuha ng normal na vector mula sa gradient.
\[
\frac{df(x)}{dx}=gradient\\
line\ gradient=\frac{y}{x}\\
Assume\ gradient=0.5\\
y=0.5\\
x=1\\
Vector\of\left\normal=
\begin{bmatrix}-1 \\0.5\end{bmatrix}\\
Vector\ of\ right\ normal=
\begin{bmatrix}1 \\-0.5\end{bmatrix}
\]
Hakbang 14: Pagsasakatuparan ng ActionScript
Kaya ang ActionScript sa ibaba ay magsasakatuparan ng matematikang konsepto na ipinaliwang sa nakaraang hakbang. Tingnan ang naka-highlight na mga linya:
private function bounce():void { var gradient:Number = quadratic_equation.diff1(intersec_points[0].x); var grad_vec:Vector2D = new Vector2D(1, gradient); var left_norm:Vector2D = grad_vec.getNormal(false); var right_norm:Vector2D = grad_vec.getNormal(); var chosen_vec:Vector2D; if (velo.dotProduct(left_norm) > 0) chosen_vec = left_norm else chosen_vec = right_norm var chosen_unit:Vector2D = chosen_vec.normalise(); var proj:Number = velo.dotProduct(chosen_unit); chosen_unit.scale(-2*proj); velo = velo.add(chosen_unit); }
Konklusyon
Bweno, salamat sa oras niyo! Kung nakita ninyong kapaki-pakinabang ito, o may mga tanong, mag-iwan ng ilang komento.