Vediamo le linee utilizzate in molti scenari. Le curve sono anche usate, anche se forse non così frequentemente - ma questo non compromette la loro importanza! In questo tutorial esamineremo più da vicino le curve, in particolare la curva quadratica e cubica, insieme ad alcune delle loro caratteristiche matematiche comunemente usate.
Diamo un'occhiata al risultato finale su cui lavoreremo. Trascina i punti rossi e vedi i gradienti cambiano in posizione.
Ed ecco un'altra demo, usando le curve cubiche, senza i gradienti:
Quadratico e cubico saranno presenti in ciascuna di queste sezioni. Diamo prima un'occhiata all'equazione delle curve. Queste equazioni sono scritte in forma polinomiale, a partire dal termine di massimo grado. Il primo è l'equazione quadratica (il grado più alto è 2); il secondo è l'equazione cubica (il grado più alto è 3).
\ [f (x) = Axe ^ 2 + Bx + C \ ... (eq \ 1) \]
\ [g (x) = Axe ^ 3 + Bx ^ 2 + Cx + D \ ... (eq \ 2) \]
Nota che A, B, C e D sono numeri reali. Quindi ora che ne siamo esperti, proviamo a visualizzarlo. Le curve grafiche saranno il nostro prossimo tentativo.
Innanzitutto, tracciamo una curva quadratica. Sono sicuro che tutti i lettori hanno tracciato una curva quadratica nella classe di matematica delle scuole superiori, ma solo per rinfrescare la memoria, presento i grafici qui sotto. Sono posizionati uno accanto all'altro per facilitare il confronto.
L'ovvia differenza è l'asse y invertito nello spazio delle coordinate Flash. Sembrano semplici nel complesso, giusto? Ok, ora siamo pronti per tracciare lo spazio delle coordinate Flash.
Per posizionare le curve quadratiche nel punto giusto, dobbiamo capire le loro equazioni corrispondenti. La curva tracciata dipende in realtà dai coefficienti dell'equazione (nel caso del quadratico, quelli sono A, B e C).
Ho incluso una presentazione Flash qui sotto in modo da poter facilmente modificare questi coefficienti e ottenere un feedback immediato.
Per studiare gli effetti dei singoli coefficienti sulla curva generale, suggerisco di seguire i passaggi seguenti per sperimentare la presentazione Flash sopra.
Un'altra osservazione interessante è che durante la seconda e terza fase di cui sopra, il punto di inflessione (cioè il punto di svolta) rimane nello stesso punto sull'asse y.
Si vede rapidamente che posizionare una curva è alquanto difficile. L'equazione utilizzata non è pratica se vogliamo, per esempio, individuare le coordinate del punto più basso di una curva.
Soluzione? Riscriveremo l'equazione in una forma desiderata. Dai un'occhiata alla seguente equazione:
\ [f (x) = P (x + Q) ^ 2 + R \]
È ancora un'equazione quadratica, ma ha assunto un'altra forma. Ora possiamo facilmente controllare i punti minimi e massimi sulla curva. Nella precedente presentazione di Flash, fai clic sul pulsante "Approccio 1" in alto a destra e gioca con i nuovi valori.
Ecco una breve spiegazione dei ruoli dei coefficienti:
Coefficiente | Ruolo |
P | Controlla la pendenza della curva. |
Q | Controlla lo spostamento del punto di svolta della curva lungo l'asse x. |
R | Controlla lo spostamento del punto di svolta della curva lungo l'asse y. |
Tuttavia, è ancora un compito difficile far passare la curva attraverso un determinato insieme di punti. Dovremmo precostituire rigorosamente su carta prima di tradurlo in codice.
Fortunatamente, c'è una soluzione migliore. Ma prima di esaminarlo, diamo ora uno sguardo all'implementazione di ActionScript.
Ecco le equazioni scritte come funzioni ActionScript (verifica Graphing.as
nel download sorgente).
funzione privata quadratic1 (x: Number, A: Number, B: Number, C: Number): Number // y = A (x ^ 2) + B (x) + C return A * x * x + B * x + C funzione privata quadratica2 (x: numero, P: numero, Q: numero, R: numero): numero // y = P * (x + Q) ^ 2 + R ritorno P * (x + Q) * ( x + Q) + R
Ed ecco una implementazione del metodo di disegno usando Graphics.drawPath ()
. Solo una nota che tutte le curve in questo articolo sono disegnate in modo simile.
Prima le variabili ...
punti var privati: Vector.= nuovo vettore. ; private var drawCommand: Vector. = nuovo vettore. ;
Ora le posizioni y, calcolate in base alle posizioni x e ai coefficienti indicati.
ridisegna la funzione privata (A: Number, B: Number, C: Number): void for (var i: int = 0; i < 400; i++) var x:Number = i - 200; points[i * 2] = x * 10 + stage.stageWidth >> 1; if (isApproach1) points [i * 2 + 1] = quadratic1 (x, A, B, C) + stage.stageHeight >> 1 else points [i * 2 + 1] = quadratic2 (x, A, B , C) + stage.stageHeight >> 1 if (i == 0) drawCommand [i] = 1; else drawCommand [i] = 2; graphics.clear (); Graphics.lineStyle (1); graphics.drawPath (drawCommand, points);
(Confuso riguardo al >>
operatore? Dai un'occhiata a questo tutorial.)
Supponiamo di avere tre punti che la curva quadratica deve attraversare; come formiamo l'equazione corrispondente? Più specificamente, come possiamo determinare i valori dei coefficienti dell'equazione? Algebra lineare viene in soccorso. Analizziamo questo problema.
Sappiamo che le equazioni quadratiche prendono sempre forma come scritto nell'eq. 1 al passaggio 1.
\ [f (x) = Axe ^ 2 + Bx + C \ ... (eq \ 1) \]
Poiché tutte e tre le coordinate date sono situate sulla stessa curva, ciascuna di esse deve soddisfare questa equazione, con gli stessi coefficienti dell'equazione della curva che stiamo cercando. Scriviamo questo in forma di equazione.
Dato tre coodinati:
Sostituisci questi valori in (eq 1). Nota che A, B, C sono sconosciuti al momento.
\ [f (x) = Axe ^ 2 + Bx + C \ ... (eq \ 1) \]
Ora, riscrivi in forma matriciale. Prendi nota che A, B, C sono le incognite per le quali stiamo risolvendo.
[Lattice]
\ begin bmatrix S_y \\ T_y \\ U_y \ end bmatrix =
\ Begin bmatrix
\ left (S_x \ right) ^ 2 & \ left (S_x \ right) & 1 \\
\ left (T_x \ right) ^ 2 & \ left (T_x \ right) & 1 \\
\ left (U_x \ right) ^ 2 & \ left (U_x \ right) & 1 \ end bmatrix
\ begin bmatrix A \\ B \\ C \ end bmatrix \\
[/ Lattice]
[Lattice]
\ Begin bmatrix
\ left (S_x \ right) ^ 2 & \ left (S_x \ right) & 1 \\
\ left (T_x \ right) ^ 2 & \ left (T_x \ right) & 1 \\
\ left (U_x \ right) ^ 2 & \ left (U_x \ right) & 1 \ end bmatrix ^ - 1
\ begin bmatrix S_y \\ T_y \\ U_y \ end bmatrix =
\ Begin bmatrix
\ left (S_x \ right) ^ 2 & \ left (S_x \ right) & 1 \\
\ left (T_x \ right) ^ 2 & \ left (T_x \ right) & 1 \\
\ left (U_x \ right) ^ 2 & \ left (U_x \ right) & 1 \ end bmatrix ^ - 1
\ Begin bmatrix
\ left (S_x \ right) ^ 2 & \ left (S_x \ right) & 1 \\
\ left (T_x \ right) ^ 2 & \ left (T_x \ right) & 1 \\
\ left (U_x \ right) ^ 2 & \ left (U_x \ right) & 1 \ end bmatrix
\ begin bmatrix A \\ B \\ C \ end bmatrix \\
[/ Lattice]
[Lattice]
\ Begin bmatrix
\ left (S_x \ right) ^ 2 & \ left (S_x \ right) & 1 \\
\ left (T_x \ right) ^ 2 & \ left (T_x \ right) & 1 \\
\ left (U_x \ right) ^ 2 & \ left (U_x \ right) & 1 \ end bmatrix ^ - 1
\ begin bmatrix S_y \\ T_y \\ U_y \ end bmatrix
= I
\ begin bmatrix A \\ B \\ C \ end bmatrix
\\
K ^ - 1 J = L
[/ Lattice]
Ovviamente possiamo usare le equazioni simultanee, ma preferisco usare le matrici perché è più semplice. (Nota del redattore: finché capisci le matrici, è così!)
Otterremo l'inverso di K e moltiplichiamo per la matrice J per ottenere L. Dopo aver risolto con successo per A, B, C, sostituiremo semplicemente l'equazione quadratica. Quindi, avremo una curva quadratica che attraversa tutti e tre i punti.
Come menzionato nel passaggio precedente, è necessario eseguire un'inversione e una moltiplicazione della matrice 3x3. ActionScript di flash.geom.Matrix
la classe non sarà in grado di aiutare in questo. Certo, abbiamo una scelta da utilizzare flash.geom.Matrix3D
, classe, ma preferisco la libreria Coral perché posso fare leva su queste classi personalizzate ed esaminare cosa sta succedendo sotto il cofano. Personalmente trovo questo molto utile ogni volta che sono in dubbio sull'uso corretto dei comandi anche dopo aver letto la documentazione dell'API.
Quindi scarica e posiziona i file corti decompressi nella cartella di origine del progetto.
Ecco un esempio del risultato. Prova a riposizionare i punti rossi e vedere la curva quadratica ridisegnata per attraversare tutti e tre i punti.
Puoi trovare lo script completo in Draw_curve.as.
Il seguente codice ActionScript è solo per abilitare i controlli del mouse sui puntini.
funzione pubblica Draw_Curve () // impostazione controlli c1 = new Circle (0xFF0000); addChild (c1); c1.x = stage.stageWidth * 0.2; c1.y = stage.stageHeight >> 1; c2 = new Circle (0xFF0000); addChild (c2); c2.x = stage.stageWidth * 0.5; c2.y = stage.stageHeight >> 1; c3 = new Circle (0xFF0000); addChild (c3); c3.x = stage.stageWidth * 0.8; c3.y = stage.stageHeight >> 1; c1.addEventListener (MouseEvent.MOUSE_DOWN, move); c1.addEventListener (MouseEvent.MOUSE_UP, move); c2.addEventListener (MouseEvent.MOUSE_DOWN, move); c2.addEventListener (MouseEvent.MOUSE_UP, move); c3.addEventListener (MouseEvent.MOUSE_DOWN, move); c3.addEventListener (MouseEvent.MOUSE_UP, move); ridisegna () move della funzione privata (e: MouseEvent): void if (e.type == "mouseDown") e.target.startDrag () e.target.addEventListener (MouseEvent.MOUSE_MOVE, update); else if (e.type == "mouseUp") e.target.stopDrag (); e.target.removeEventListener (MouseEvent.MOUSE_MOVE, aggiornamento); aggiornamento della funzione privata (e: MouseEvent): void redraw ();
Il nucleo sta nel ridisegnare
funzione. Ho evidenziato le operazioni della matrice e la funzione quadratica per il processo di ridisegno.
funzione privata redraw (): void K = new Matrix3d (c1.x * c1.x, c1.x, 1, 0, c2.x * c2.x, c2.x, 1, 0, c3.x * c3 .x, c3.x, 1, 0, 0, 0, 0, 1); K.invert () L = new Matrix3d (c1.y, 0, 0, 0, c2.y, 0, 0, 0, c3.y, 0, 0, 0, 0, 0, 0, 0); L.append (K); graphics.clear (); punti var: Vector.= nuovo vettore. ; var cmd: Vector. = nuovo vettore. ; per (var i: int = 0; i < 200; i++) //current x var x:Number = i * 2; //f(x) = A (x^2) + B (x) + C var y:Number = L.n11* x* x + L.n21 * x + L.n31 ; points.push(x, y); if (i == 0) cmd.push(1); else cmd.push(2); graphics.lineStyle(1); graphics.drawPath(cmd, points);
Quindi puoi vedere che la matrice K è stata inizializzata e invertita prima di essere aggiunta alla matrice J.
Il aggiungere()
la funzione moltiplica la matrice corrente, J, con la matrice di input, K, posizionata alla sua sinistra. Un altro dettaglio degno di nota è che non utilizziamo tutte le righe e le colonne nelle matrici K e J. Tuttavia, poiché l'inversione della matrice può avvenire solo con una matrice quadrata, dobbiamo riempire la 4ª riga, 4 ° elemento colonna di K con 1. (Non è necessario farlo per J perché non abbiamo bisogno della sua inversione nel nostro calcolo. Quindi, puoi vedere tutti gli altri elementi sono 0 tranne la prima colonna.
Quindi è tutto per disegnare curve quadratiche. Passiamo alle curve cubiche.
Di nuovo, avremo una piccola revisione del grafico di queste curve. Dai un'occhiata alla seguente immagine:
Quando confronti questa curva con quella del quadratico, noterai che è più ripida e che una parte della curva è al di sotto dell'asse x. Una metà è specchiata verticalmente, rispetto a un quadratico.
Ho incluso la seguente presentazione Flash per farti sperimentare i coefficienti di un'equazione cubica. Prova a regolare il valore di A da positivo a negativo e osserva la differenza nella curva prodotta.
Ecco la sezione importante dell'implementazione del grafico sopra:
ridisegna la funzione privata (A: Number, B: Number, C: Number, D: Number): void for (var i: int = 0; i < 400; i++) var x:Number = i - 200; points[i * 2] = x * 10 + stage.stageWidth >> 1; punti [i * 2 + 1] = cubico1 (x, A, B, C, D) + stage.stageHeight >> 1 if (i == 0) drawCommand [i] = 1; else drawCommand [i] = 2; graphics.clear (); Graphics.lineStyle (1); graphics.drawPath (drawCommand, points); private function cubic1 (x: Number, A: Number, B: Number, C: Number, D: Number): Number // y = A (x ^ 3) + B (x ^ 2) + C (x) + D ritorno A * x * x * x + B * x * x + C * x + D
Di nuovo, è difficile posizionare la curva cubica in base a una serie di punti che attraversa. Ancora una volta, ci riferiamo all'algebra lineare per un'alternativa.
Sappiamo dal punto 6 che i coefficienti di un'equazione di secondo grado possono essere calcolati sulla base di tre punti dati e che la curva disegnata da esso attraverserà quei punti. Un approccio simile può essere eseguito con qualsiasi quattro dati i punti per ottenere un'equazione cubica:
Sostituisci queste coordinate in (eq 2). Nota che A, B, C, D sono sconosciuti.
\ [g (x) = Axe ^ 3 + Bx ^ 2 + Cx + D \ ... (eq \ 2) \]
Ma ora ci occuperemo di una matrice 4x4 invece di una matrice 3x3:
\ (
\ begin bmatrix S_y \\ T_y \\ U_y \\ V_y \ end bmatrix =
\ Begin bmatrix
\ left (S_x \ right) ^ 3 & \ left (S_x \ right) ^ 2 & \ left (S_x \ right) & 1 \\
\ left (T_x \ right) ^ 3 & \ left (T_x \ right) ^ 2 & \ left (T_x \ right) & 1 \\
\ left (U_x \ right) ^ 3 & \ left (U_x \ right) ^ 2 & \ left (U_x \ right) & 1 \\
\ left (V_x \ right) ^ 3 & \ left (V_x \ right) ^ 2 & \ left (V_x \ right) & 1 \ end bmatrix
\ begin bmatrix A \\ B \\ C \\ D \ end bmatrix \\
P = QR \\
Q ^ - 1 P = Q ^ - 1 QR \\
Q ^ - 1 P = IR \\
Q ^ - 1 P = R
\)
Ora utilizzeremo tutti gli elementi nella matrice 4x4 per Q e l'intera prima colonna per P. Then Q è inverso e applicato a P.
Di nuovo, impostiamo i controlli del mouse per consentire il trascinamento di quei punti. Quando uno di questi punti viene trascinato, il ricalcolo e il ridisegno della curva si verificano costantemente.
funzione pubblica Draw_Curve2 () // impostazione controlli c1 = new Circle (0xFF0000); addChild (c1); c1.x = stage.stageWidth * 0.2; c1.y = stage.stageHeight >> 1; c2 = new Circle (0xFF0000); addChild (c2); c2.x = stage.stageWidth * 0.4; c2.y = stage.stageHeight >> 1; c3 = new Circle (0xFF0000); addChild (c3); c3.x = stage.stageWidth * 0.6; c3.y = stage.stageHeight >> 1; c4 = new Circle (0xFF0000); addChild (c4); c4.x = stage.stageWidth * 0.8; c4.y = stage.stageHeight >> 1; c1.addEventListener (MouseEvent.MOUSE_DOWN, move); c1.addEventListener (MouseEvent.MOUSE_UP, move); c2.addEventListener (MouseEvent.MOUSE_DOWN, move); c2.addEventListener (MouseEvent.MOUSE_UP, move); c3.addEventListener (MouseEvent.MOUSE_DOWN, move); c3.addEventListener (MouseEvent.MOUSE_UP, move); c4.addEventListener (MouseEvent.MOUSE_DOWN, move); c4.addEventListener (MouseEvent.MOUSE_UP, move); ridisegnare (); move della funzione privata (e: MouseEvent): void if (e.type == "mouseDown") e.target.startDrag () e.target.addEventListener (MouseEvent.MOUSE_MOVE, aggiornamento); else if (e.type == "mouseUp") e.target.stopDrag (); e.target.removeEventListener (MouseEvent.MOUSE_MOVE, aggiornamento); aggiornamento della funzione privata (e: MouseEvent): void redraw ();
ridisegnare
è la funzione cruciale in cui tutto è successo.
funzione privata redraw (): void var left: Matrix3d = new Matrix3d (c1.x * c1.x * c1.x, c1.x * c1.x, c1.x, 1, c2.x * c2.x * c2.x, c2.x * c2.x, c2.x, 1, c3.x * c3.x * c3.x, c3.x * c3.x, c3.x, 1, c4.x * c4. x * c4.x, c4.x * c4.x, c4.x, 1); left.invert () var right: Matrix3d = new Matrix3d (c1.y, 0, 0, 0, c2.y, 0, 0, 0, c3.y, 0, 0, 0, c4.y, 0, 0 , 0); right.append (sinistra); // f (x) = A (x ^ 3) + B (x ^ 2) + C (x) + D graphics.clear (); punti var: Vector.= nuovo vettore. ; var cmd: Vector. = nuovo vettore. ; per (var i: int = 0; i < 200; i++) var x:Number = i * 2; var y:Number = right.n11 * x * x * x+ right.n21 * x * x+ right.n31 * x + right.n41; points.push(x, y); if (i == 0) cmd.push(1); else cmd.push(2); graphics.lineStyle(1); graphics.drawPath(cmd, points);
Infine, diamo un'occhiata al prodotto. Fare clic e spostare i punti rossi per vedere la curva cubica disegnata per passare attraverso tutti questi punti.
Abbiamo appena finito di disegnare polinomi di grado 2 e 3 (quadratico e cubico). Dalla nostra esperienza, possiamo prevedere che il calcolo per il polinomio di grado 4 (quintic) richiederà cinque punti, che richiedono una matrice 5x5, e così via per i polinomi di grado ancora più elevato.
Sfortunatamente, Corallo
e flash.geom.Matrix3D
ammetti solo matrici 4x4, così avrai scritto la tua classe se il bisogno arriverà. Raramente è richiesto nei giochi, però.
Proviamo ad applicare le nostre conoscenze per dividere le regioni sul nostro palcoscenico. Ciò richiede una revisione delle disuguaglianze di equazione. Guarda l'immagine qui sotto.
Questa immagine sopra mostra una curva che divide le regioni in due:
Non è difficile capire questo concetto. In effetti, hai già sperimentato su questo nel passaggio 11 quando hai modificato i coefficienti della formula cubica. Immagina, nel sistema di coordinate, che ci sia un numero infinito di curve, tutte differenziate solo da un leggero cambiamento in D:
Quindi ecco il campione di output per la curva quadratica. Puoi provare a spostare il punto rosso e vedere le regioni colorate.
Ecco l'importante snippet di ActionScript. Guarda lo script completo in Region_Curve.as
funzione privata redraw (): void var left: Matrix3d = new Matrix3d (c1.x * c1.x, c1.x, 1, 0, c2.x * c2.x, c2.x, 1, 0, c3. x * c3.x, c3.x, 1, 0, 0, 0, 0, 1); left.invert () var right: Matrix3d = new Matrix3d (c1.y, 0, 0, 0, c2.y, 0, 0, 0, c3.y, 0, 0, 0, 0, 0, 0, 0 ); right.append (sinistra); // D = A (x ^ 2) + B (x) + C per ogni (oggetto var: Cerchio sullo sfondo) var D: Number = right.n11 * item.x * item.x + right.n21 * item .x + right.n31; //trace(background[i].y); if (item.y> D) item.color = 0; else item.color = 0xAAAAAA;
Ecco il campione per quanto riguarda la curva cubica.
E l'implementazione che ne deriva. Ancora una volta, la sceneggiatura completa è in Region_Curve2.as
// D = A + B (x) + C (x ^ 2) per ogni (oggetto var: Cerchio sullo sfondo) var D: Number = right.n11 * item.x * item.x * item.x; + right.n21 * item.x * item.x + right.n31 * item.x + right.n41 //trace(background[i].y); if (item.y> D) item.color = 0; else item.color = 0xAAAAAA;
Che ne dici di alcuni ritocchi per cambiare il colore tra le diverse curve? Ancora una volta, fare clic con il mouse sui punti rossi e vedere i cambiamenti di gradiente sullo schermo.
Ecco l'importante snippet di ActionScript estratto da Region_Curve3.as
. Prima di tutto vorremmo scoprire l'offset massimo e minimo dalla curva originale.
var max: Number = 0; var min: Number = 0; var Ds: Vector.= nuovo vettore. ; // D = A (x ^ 2) + B (x) + C per ogni (oggetto var: Cerchio sullo sfondo) var D: Number = right.n11 * item.x * item.x + right.n21 * item .x + right.n31; var offset: Number = item.y - D; Ds.push (offset); se (item.y> D && offset> max) max = offset; altrimenti se (item.y < D && offset < min) min = offset;
Una volta fatto, lo applicheremo per colorare i singoli punti.
// variazioni di colore in base al colore var offset: Number for (var i: int = 0; i < background.length; i++) if (Ds[i] > 0) color = Ds [i] / max * 255 // calcolo del colore nello slot in background [i] .color = color<<16 | color<<8 | color; //define a grayscale else if (Ds[i] < 0) color = Ds[i] / min * 255; background[i].color = color<<16; //define a gradient of red
In modo che tutto per il disegno di curve. Avanti, trovando le radici di una curva quadratica e cubica. Grazie per aver letto. Condividi se vedi alcune applicazioni reali che sfruttano questo tutorial.