Sign in Join
Wiki copytemporary

TAChart Tutorial: ColorMapSeries, Zooming/fi: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Johdanto
22
33![](/wiki-images/0/02/Mandelbrot_final.png)
44
55["Mandelbrotin joukko"](http://fi.wikipedia.org/wiki/Mandelbrotin_joukko), nimetty Benoît Mandelbrotin mukaan, on niin sanottu "fraktaali" -- kaksiulotteinen muoto, joka on tunnettu siitä että se on itsesimilaarinen eri mittakaavoissa. Fraktaalin suurentaminen paljastaa pienimuotoisia yksityiskohtia joka ovat samanlaisia kuin laajamittaiset ominaisuudet. Tässä opetusohjelmassa käytetään [[TAChart]]-komponenttia piirtämään Mandelbrot joukon **värikarttakuvaajan** avulla ja käytetään erilaisia zoomausta tekniikoilla, kuten zoomausta vetämällä tai asettamalla **extent** historia. Kuten tavallista, tämä vaatii perustiedot työskennellä TAChart-komponentin kanssa jonka perustiedot saadaan kun käydään läpi [[TAChart Tutorial: Getting started|"Aloitus" opetusohjelma]] . Ja tietenkin, pitää olla perustiedot Lazarus IDE:stä ja Object Pascal kielestä.
66
77## Värikarttakuvaajan (TColormapSeries) käyttö
88
99Mikä on [[TAChart documentation|TColorMapSeries]]? Normaalisti työskennellään kuvaajien kanssa jotka sisältävät kaksiulotteista dataa - yhdellä akselilla on *X*- koordinaatit ja toisella *y*:n arvot, jotka on määritetty *x*:n arvojen suhteen. Värikarttakuvaaja (`TColorMapSeries`) on tästä poikkeus: se näyttää kolmiulotteista dataa : meillä on piste *xy* ja kolmas arvo, sen korkeus joka liitetään *xy*-tasoon. Usein 3D pisteitä, katsotaan kuin vuoria maiseman yläpuolella, pohjan tasossa. Valitettavasti TAChart ei voi piirtää 3D-näkymiä. Mutta on olemassa vaihtoehto: korkeus, alustan tason yläpuolella voi voidaan kuvata värillä, tämä tarkoittaa että kaavio täyttää xy-tason väreillä, jotka vastaavat kolmannen tason koordinaatteja.
1010
1111Värikarttakuvaaja (`TColorMapSeries`) on funktionaalinen kuvaaja, mikä tarkoittaa sitä että se ei voi piirtää mielivaltaista dataa, vaan dataa, jotka voidaan laskea funktiona. Tätä tarkoitusta varten kuvaajalla on tapahtuma `OnCalculate` jota kutsutaan jokaisen (*x*, *y*) pisteelle siirtämään funktion arvo. Tässä mielessä `TColorMapSeries` on samanlainen kuin funktiokuvaaja (`TFuncSeries`) jonka käyttöä opetettiin [[TAChart Tutorial: Function Series/fi|toisessa opetusohjelmassa]] .
1212
1313Toinen "perusraaka-aine" on `ColorSource` joka kuvaa funktion arvot värin. Tähän tarkoitukseen on kätevä käyttää `TListChartSource`-komponentti. Yleisesti, se tallentaa *x* ja *y*:n arvojen kanssa väriarvon ja kuvaavan etiketin `TChartDataItem`, mutta värikarttakuvaajaa varten tarvitaan vain *x*- ja väri merkintöjä.
1414
1515Valmis aloittamaan?
1616
1717Luo uusi projekti ja lisää client-aligned `TChart`-komponentti. Älä tee ikkunasta liian suurta, koska tämän opetusohjelman projekti vaatii paljon laskentaa ja suuri määrä pikseleitä heikentää suorituskykyä ... Kaksoisklikkaa kaaviota avataksesi "muokkaa kuvaajia" ikkunan ja lisää "Värikarttakuvaaja" kaavioon. Seuraavaksi pudota `TListChartSource` lomakkeelle. Tämä on värin lähde Värikarttakuvaajalle (ColorMapSeries). Joten, nimeä se "`ColorSource`" ja liitä se vastaavaan omaisuuteen kuvaajassa.
1818
1919![](/wiki-images/3/32/Madelbrot_ColorMapSeries.png)
2020
2121## Värikarttaan tutustuminen
2222
2323Jotta saadaan joitakin perehtyneisyyttä tästä uudesta ympäristöstä, voidaan aloittaa tekemällä yksinkertainen esimerkki: käytetään värikarttakuvaajaa piirtämään liukuvärjäys *x*-akselille.
2424
2525Aluksi kirjoitetaan ColorMapSeries:n tapahtuman käsittelijä `OnCalculate`. Tämä on helppoa, koska halutaan vain yksinkertainen lineaarinen gradientti eli liukuvärjäys:
2626
2727``` pascal
2828procedure TForm1.Chart1ColorMapSeries1Calculate(const AX, AY: Double;
2929 out AZ: Double);
3030var
3131 ext: TDoubleRect; // unit TAChartUtils.pas
3232begin
3333 ext := Chart1.GetFullExtent;
3434 AZ := (AX - ext.a.x) /(ext.b.x - ext.a.x);
3535end;
3636```
3737
3838Jotta ollaan riippumattomia kaavion koosta normalisoidaan *x*-koordinaatti alueelle *x* datat ( [[TAChart documentation|graph units]]). *X* alue voidaan laskea kaavion [[TAChart documentation|FullExtent]] - tämä on suorakulmio kaksinkertaisen tarkkuuden arvot on määritelty kulmassa oleva kaavion piirtämällä suorakulmio ennen kuin zoomausta tai panorointia tehdään. Normalisoituminen kuten yllä varmistaa, että AZ on 0 vasemmalla ja 1 oikealla *x*-akselin lopussa.
3939
4040Lopuksi täytyy täyttää ColorSource asetus liukuvärjäyksellä. Tämä on erittäin helppoa, koska ColorMapSeries tekee kaikki interpoloinnit jos sen omaisuus `Interpolate` asetetaan arvoon `true`.
4141
4242Likuvärjäyksen määrittely aloitetaan arvosta 0,0 ja se määritetään siniseksi väriksi. Lopussa liukuvärjäys vastaa arvoa 1,0 ja sen pitäisi näkyä keltaisena. Nämä tehtävät tehdään aliohjelmassa `PopulateColorSource` jota kutsumme `OnCreate` lomakkeen tapahtumassa; käytämme erillisessä aliohjelmaa, koska joitakin muutoksia tehdään koko tämän opetusohjelma ajan ja haluataan pitää asiat erillään.
4343
4444``` pascal
4545procedure TForm1.FormCreate(Sender: TObject);
4646begin
4747 PopulateColorSource;
4848end;
4949
5050procedure TForm1.PopulateColorSource;
5151const
5252 DUMMY = 0.0;
5353begin
5454 with ColorSource do begin
5555 Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen
5656 Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen
5757 end;
5858end;
5959```
6060
6161Johtuen `TListChartSource.Add` syntaksista täytyy antaa arvoja *y*-koordinaatille ja marks tekstille, käytetään siihen vakiota `DUMMY` ja tyhjää merkkijonoa koska niitä tarvita.
6262
6363Ajetaan ohjelma. Jos ei nähdä liukuvärjäystä niin ehkä on unohtunut aktivoida ColorMapSource:n `Interpolate` asetus. Jos hyvin tarkkaan katsotaan niin nähdään joitakin värisävyjen kapeita ryhmittelyjä erityisesti keskustan siirtymäalueella. Tämä johtuu ColorMapSource:n ominaisuuksista `StepX` ja `StepY` jotka ovat edelleen niiden oletusarvossa 4. Tämä tarkoittaa sitä, että xy-tasoa ei tarkisteta pikseli kerrallaan, vaan 4x4 pikselin lohkoissa, tämä nopeuttaa piirtämistä. Asetamalla nämä arvoon 1 päästään eroon ryhmittelystä. Parantunut tarkkuus on myös edullista Mandelbrot joukolle myöhemmin. Kuitenkin se hidastaa ohjelman suoritusta, joka voi olla varsin dramaattista, jos on hidas tietokone ...
6464
6565![](/wiki-images/5/52/Madelbrot_FirstGradient.png) ![](/wiki-images/f/fc/Mandelbrot_TwoGradients.png)
6666
6767Mennään pidemmälle ja lisätään toinen pivot liukuvärjäykseen. Entä punainen keskellä vastaamaan vaikkapa 0,3? Laitetaan toinen kutsu `Add` osaksi `PopulateColorSource` aliohjelmaa. Koska interpolointi vaatii lajitellun luettelon kannattaa lisätä uusi väri muiden väliin tai sitten pitäisi kutsua `Sort` väriä-arvo-parien lisäämisen jälkeen. Tuloksena on edellä esitetty kolmivärinen liukuvärjäys, käytämme sitä, kun tehdään Mandelbrotin joukkoa.
6868
6969``` pascal
7070procedure TForm1.PopulateColorSource;
7171const
7272 DUMMY = 0.0;
7373begin
7474 with ColorSource do begin
7575 Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen
7676 Add(0.3, DUMMY, '', clRed); // 0.3 --> punainen
7777 Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen
7878 end;
7979end;
8080```
8181
8282## Mandelbrotin joukko
8383
8484Joten mikä on Mandelbrotin joukko? Karkeasti ottaen se on joukko pisteitä *xy*-tasolla jotka noudattavat tiettyä sääntöä, kuten ympyrä, jonka sääntö on, että kaikki ympyrän pisteet(esim joukon) on oltava samalla etäisyydellä origosta.
8585
8686Niin Mandelbrotin joukon sääntö on vähän monimutkaisempi. "Kompleksinen" maailma on ymmärrettävä tässä kaksitahoissa mielessä: monimutkainen merkityksessä "monimutkainen", mutta myös monimutkainen matemaattisessa mielessä, että kohtia *xy* käsitellään kuten kompleksilukuja. Jos et ole perehtynyt kompleksilukuihin, älä anna periksi - vältämme täysin laskelmat näillä "oudoilla" numeroilla.
8787
8888### Laskeminen
8989
9090Paras tapa ymmärtää Mandelbrotin joukko on tehdä sen rakenne. Käytetään seuraavaa reseptiä jokaiselle 2d pisteelle *xy* tasolla; Näistä lähtöpisteitä on kutsutaan c = (c<sub>x</sub>, c<sub>y</sub>).
9191
92921. Aloita liittämällä c toiseen pisteeseen z = (z<sub>x</sub>, z<sub>y</sub>) = (c<sub>x</sub>, c<sub>y</sub>).
93932. Laske z:n "neliö" seuraavalla kaavalla: z<sup>2</sup> = (z<sub>x</sub><sup>2</sup> - z<sub>y</sub><sup>2</sup>, 2 * z<sub>x</sub> * z<sub>y</sub>) - tämä kaava voi näyttää hieman oudolta, mutta jos on perehtynyt Kompleksinumeroihin niin huomataan, että se on tapa, miten lasketaan kompleksiluvun neliö. (Jos ei ole perehtynyt niin pidä se annettuna.)
94943. Lisää sitten c:n koordinaatit c kuin `z`<sup>`2`</sup>. Tämän seurauksena vaihe on z<sup>2</sup> + c = (z<sub>x</sub><sup>2</sup> - z<sub>y</sub><sup>2</sup> + c<sub>x</sub>, 2 * z<sub>x</sub> * z<sub>y</sub> + c<sub>y</sub>)
95954. Nyt otetaan tämä tulos ja laitetaan se vaiheen 2 laskuun jälleen uutena z:n arvona
96965. Toista tämä aliohjelma uudestaan ​​ja uudestaan. Tämän seurauksena piste z seuraa jonkinlaisen lentoradan *xy* tasossa. Kuvassa näytämme muutamia esimerkkejä, jotka jäljittää:
9797 - ![](/wiki-images/a/a6/Mandelbrot_Tracks.png) Punainen ja fuksia käyrät lopulta siirtää pois alkuperä, nämä polut ovat **"rajaton"** (**"unbounded"**). Voidaan osoittaa, että kun polku on ylittänyt kriittisen etäisyyden 2 päässä alkuperää se ei koskaan palaa takaisin ja välttyy äärettömyyteen. Yleensä laskenta laskee toistojen kunnes etäisyys origosta on yli 2. Iteraatioiden lukumäärä on kartoitettu värillä, jota käytetään piirtämän pikselin lähtöpisteestä c.
9898 - Sininen polku, toisaalta, suppenee kohti alkuperää. Vihreä käyrä ei lähentyvät, mutta pysyy paeta säteellä. Molemmat tapaukset ovat nimeltään **"rajoitettujen"** (**"bounded"**). Iteratiivinen laskenta menisi loputtomiin. Siksi se pysäytetään iteraatioiden maksimimäärään. Lähtöpisteet c näille liikeradoille sanotaan kuuluvan Mandelbrotin joukkoon ja piirretään mustalla värillä.
9999
100100Vaikka tämä kuvaus voi kuulostaa vähän hankalalta niin vain muutama rivi Pascal koodia tarvitaan laskennassa. Seuraava funktio määrittää, onko piste c Mandelbrotin joukossa vai ei. Se palauttaa tarvittavien iteraatioiden määrän ja pisteen koordinaatit kun viimeinen iteraatio on suoritettu.
101101
102102``` pascal
103103const
104104 MANDELBROT_NUM_ITERATIONS = 100;
105105 MANDELBROT_ESCAPE_RADIUS = 2.0;
106106 MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS);
107107
108108function InMandelbrotSet(c:TDoublePoint; out Iterations:Integer; out z: TDoublePoint): Boolean;
109109var
110110 j: Integer;
111111begin
112112 Iterations := 0;
113113 z := DoublePoint(0.0, 0.0); // unit TAGeometry.pas
114114 for j:=0 to MANDELBROT_NUM_ITERATIONS-1 do begin
115115 z := DoublePoint(
116116 sqr(z.X) - sqr(z.Y) + c.X,
117117 2 * z.X * z.Y + c.Y
118118 );
119119 if sqr(z.X) + sqr(z.Y) > MANDELBROT_LIMIT then begin
120120 Result := false;
121121 // point did escape --> c ei kuulu Mandelbrotin joukkoon
122122 exit;
123123 end;
124124 inc(Iterations);
125125 end;
126126 Result := true;
127127end;
128128```
129129
130130### Piirtäminen
131131
132132Nyt haluamme piirtää Mandelbrotin joukon. Tiedät mitä tehdä? Kyllä - täytyy kirjoittaa vastaava käsittelijä `OnCalculate`. Tapahtumakäsittelijässä kutsutaan funktiota `InMandelbrotSet`. Jos piste siirtyi tapahtumakäsittelijän on Mandelbrotin joukkoon asetaan sen väri mustaksi, jos ei niin jaetaan toistojen määrän suurimman iteraatioiden määrällä ja saadaan arvo väliltä 0 ja 1, joka on vastaava merkintä meidän ColorSource . Oh - mutta miten antaa Mandelbrotin joukon mustan värin pisteitä? Lisätään vain uusi numero ColorSource väripariksi joka yhdistää `clBlack`:n esimerkiksi -1.
133133
134134``` pascal
135135procedure TForm1.PopulateColorSource;
136136const
137137 DUMMY = 0.0;
138138begin
139139 with ColorSource do begin
140140 Clear;
141141 Add(-1.0, DUMMY, '', clBlack); // -1.0 --> musta
142142 Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen
143143 Add(0.3, DUMMY, '', clRed); // 0.3 --> punainen
144144 Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen
145145 end;
146146end;
147147
148148procedure TForm1.Chart1ColorMapSeries1Calculate(const AX, AY: Double;
149149 out AZ: Double);
150150var
151151 iterations: Integer;
152152 z: TDoublePoint;
153153begin
154154 if InMandelBrotSet(DoublePoint(AX, AY), iterations, z) then
155155 AZ := -1
156156 else
157157 AZ := iterations / MANDELBROT_NUM_ITERATIONS;
158158end;
159159```
160160
161161Ja se, mikä on tämän tuloksena - katso vasen kuva:
162162
163163![](/wiki-images/e/eb/Madelbrot_FirstChart.png) ![](/wiki-images/9/9e/Mandelbrot_SecondChart.png)
164164
165165Erittäin kiva. Mutta kuten tavallista niin ensimmäinen tulos ei ole vielä paras mahdollinen. Tässä kaksi kohtaa, joita voidaan parantaa:
166166
167167- Kuva on **leikattu**. Tämä johtuu siitä, ettei määritelty laskennassa x:n ja y:n aluetta mitä ColorMapSeries käyttää. Yleisesti Mandelbrotin joukko nähdään parhaiten, kun x:n arvot ovat välillä -2,2 ja 0,8, sekä vastaavasti y:n arvot ovat välillä -1.5 ja 1.5. Kirjoita nämä numerot kaavion `Extent`:n kenttiin `XMin, XMax, YMin` ja `YMax` sekä aseta kentät `UseXMin, UseXMax, UseYMin` ja `UseYMin` arvoon `true` jotta nämä akselien raja-arvot aktivoidaan. Voidaan yhtä hyvin käyttää kuvaajan `Extent` ominaisuutta, mutta sitten pitäisi asettaa kaavion `Margins` arvoon 0, ei-täytetyn taustan poistamiseksi lähellä akseleita.
168168
169169- Kuva näyttää jotenkin **vääristyneeltä**, jos sitä verrataan kuviin [1](http://en.wikipedia.org/wiki/Mandelbrot_set). Tämä tapahtuu, koska *x* ja *y*-akselilla on eri yksikköpituudet. Vääristymisen välttämiseksi 0:n ja 1:n välinen etäisyys on oltava yhtä suuri molemmille akseleilla. Tietenkin voidaan alustaa lomakkeen leveys ja korkeus oikein, mutta käyttäjä voi muuttaa sen muotoa, ja se vääristäisi kuvaa uudelleen. Kuitenkin `TChart`-komponentilla on käytännöllinen ominaisuus ota käyttöön "neliö" koordinaatisto: aseta `Proportional` arvoon `true`. Tällä asetuksella laajuutta x- ja y-akselit säätyy automaattisesti aina samankokoiseen yksikköön.
170170
171171Tulos näiden muutoksien jälkeen näkyy yläpuolella oikeassa kuvassa. Siinä voidaan huomata, että *x*-akselin alue on laajempi kuin oli pyydetty. Tämä on seurausta `Proportional` asetuksesta koska kuvasuhde ei ole ikkunassa yhteensopiva miten *x*- ja *y*-alueet asetetaan kaavion `Extent` ominaisuudessa.
172172
173173Ennen kuin jatketaan opetusohjelmaa, niin "kotitehtävänä" voisi olla tälläinen : Muuta ohjelma niin, että Mandelbrotin joukko ei ole musta, mutta näyttää etäisyyden mukaan värit liikeradan origosta kun iterointi keskeytetään.
174174
175175## Zoomaus ja vieritys
176176
177177Johdannossa mainittiin, että Mandelbrotin joukko on itsestään samanlainen kuin suurennetussa mittakaavassa. Tämä näkeminen edellyttää zoomausta - ja tämä tehdään opetusohjelman seuraavassa osassa.
178178
179179### Sisäänrakennettu zoomaus
180180
181181`TChart` komponentissa on sisäänrakennettuna zoomaus ominaisuudet. Täytyy vain vetää suorakulmio hiirellä ylhäältä-vasemmalta oikeaan alakulmaan alueelle, jota halutaan suurentaa ja pitää hiiren vasenta painiketta alhaalla, vetäessä. Palauta alkuperäinen näkymä vetämällä johonkin toiseen suuntaan tai klikkaa kuvaa.
182182
183183![](/wiki-images/2/23/Mandelbrot_Zooming.png) ![](/wiki-images/f/f4/Mandelbrot_ZoomingResult.png) ![](/wiki-images/3/34/Mandelbrot_DeepZoom.png)
184184
185185Tietenkin voidaan käyttää uutta suurennettua kuvaa zoomata siitä uudestaan ​​ja uudestaan. Kuitenkin jossain zoomaustasolla, akselitunnukset pitenevät ja voi lopulta olla päällekkäisiä. Tämä ei näytä hyvältä. Tarvitsemmeko akselit ollenkaan? Ei - ne saadaan pois päältä menemällä komponenttimuokkaimessa vasemmalle ja ala akselille ja asettamalla niiden omaisuus `Visible` arvoon `false`.
186186
187187Mutta ehkä pitäisi olla joitakin viitteitä koosta näyttöikkunassa. Käytössä olevan suurennuksen voidaan näyttää TLabel-komponentilla. Jotta tilaa tulisi muillekin info teksteille myöhemmin tässä opetusohjelmassa, lisätään TPanel komponentti niitä varten. Kohdista tämä "info paneeli" oikealle (`Align` arvoon `alRight`) ja poista sen `Caption`. Jotta saadaan riittävän suuri kaavion uudelleen pitänee muuttaa lomakkeen kokoakin. Lisää label paneelin yläosaan ja nimeä se `LblMagnification`.
188188
189189### Extents
190190
191191Miten saada nykyinen suurennus? Näkymä kuvataan TAChart useilla [[TAChart documentation|"extents"]]:llä nämä ovat suorakulmioita kuin `TRect`, mutta kulman pisteet on annettu liukulukuina. Tämä data on tyypiltään `TDoubleRect` ja se on määritelty käännösyksikössä `TAChartUtils`. Esillä on jo ollut funktio `GetFullExtent` on `TChart` joka palauttaa zoomattoman / vierittämättömän näkymän. Zoomauksen tai vierityksen jälkeinen näkymä saadaan `CurrentExtent` tai `LogicalExtent` ominaisuuksilla. Molemmat ovat suorakulmioita ja hyvin samankaltaisia mutta ensinmainittu on hieman suurempi kuin jälkimmäinen, koska se huolehtii myös tarvittavan tilan akselin merkinnöille ja sisemmät kaavio marginaalit. Koska tämä ylimääräinen tila ei oteta huomioon täysimääräisesti, täytyy verrata leveydet full extent / looginen extent ja laskea suurennus. Korkeuksia ei tarvitse miettiä, koska `Proportional` on asettu kaavion.
192192
193193On huomattava, että ulottuvuudet (extent) annetaan aina [[TAChart documentation|graph unit]]:na, eli alla olevaan kaavion koordinaatistoon. Koska emme käytä [[TAChart documentation|TChartTransformations]] niin tämä on sama kuin systeemin koordinaatisto näyttäisi akselit (akselikoordinaatit).
194194
195195Milloin päivitetään suurennusteksti? Aina kaavion koossa (extent) tapahtuu muutoksia. TChart tarjoaa kaksi tapahtumaa tässä kohdassa: `OnExtentChanged` ja `OnExtentChanging`. Molemmat tapahtumat syntyvät kun koko on jo muuttunut, `OnExtentChanged` kutsutaan piirustuksen rutiinin sisällä, `OnExtentChanging` kutsutaan ennen piirtämistä. Ero on tärkeää, jos tapahtumakäsittelijä aloittaisi uudelleen piirtää kaavion jälleen - tämä voi lukita sovelluksen ... Tässä sovelluksessa ero ei ole merkittävä, joten valitaan `OnExtentChanging`.
196196
197197``` pascal
198198procedure TForm1.Chart1ExtentChanged(ASender: TChart);
199199var
200200 cex, fex: TDoubleRect;
201201 factor: double;
202202begin
203203 cex := Chart1.CurrentExtent;
204204 fex := Chart1.GetFullExtent;
205205 if cex.b.x = cex.a.x then exit;
206206
207207 factor := (fex.b.x - fex.a.x) / (cex.b.x - cex.a.x);
208208 if factor > 1e6 then
209209 LblMagnification.Caption := Format('Magnification: %.0e', [factor])
210210 else
211211 LblMagnification.Caption := Format('Magnification: %0.n', [factor]);
212212end;
213213```
214214
215215![](/wiki-images/2/25/Mandelbrot_ExtremeMag.png)
216216
217217Tämä on eräs mahdollinen tapahtumakäsittelijän versio. Koska hyvin suuri suurennuskertoimia on vaikea lukea niin siirrytään käyttämään suurennuksen mennessä yli yhden (1) miljoonan eksponentiaalista numeerista merkintätapaa.
218218
219219### Zoomaus kohti ääretöntä ...
220220
221221Kokeillaan suurennoksia - kuva oikealla suurennettu yli yhden (1) miljardin kerran (1E9). Ja on mahdollista löytää paikkoja, joissa voit suurennoksia on 1E14 kertaa ennen kuva on "ruma". Jos mietitään tätä numeroa: jos alkuperäinen ei-zoomattu ikkuna olisi 10 cm poikkipituudeltaan - niin tällä suurennuksella se olisi mitattuna 1E13 metriä. Tämä vastaisi kooltaan koko aurinkokuntaa! Ei ole järkevää zoomata enempää, koska me saavuttaneet TAChart sisäisesti käyttämän kaksinkertainen tarkkuuden rajan. Kuitenkin teoriassa, se voi mennä ja ja ...
222222
223223### Kaavion muokkaustyökalujen käyttö
224224
225225Jos halutaan siirtää näkymää hieman vasemmalle tai oikealle samalla suurennuksella niin Tätä kutsutaan vierittämiseksi tai panoroinniksi. Kuvan vierittäminen onnistuu vetämällä sitä hiiren oikealla painikkeella. Lazaruksen versiossa 1.0 ei ollut sisäänrakennettua vieritys tukea. Mutta siihenkin sen voi tehdä [[TAChart documentation|kaavion muokkaustyökaluilla]].
226226
227227Tässä ei mennä yksityiskohtiin, mitä kaavion muokkaustyökalut (ChartTools) ovat ja mitä niillä voi yleensä tehdä. Katso sen[[TAChart Tutorial: Chart Tools|opetusohjelmaa]] jos ne eivät ole tuttuja.
228228
229229![](/wiki-images/4/40/TChartToolset-Icon.png) Aloituksessa lisätään ChartToolSet komponentti lomakkeelle ja linkitetään sen ominaisuus `Toolset` kaavion. Sitten kaksoisklikkaamalla ChartToolSet komponenttia avautuu muokkaustyökalut-ikkuna ja valitaan lisää-painikkeen "takaa" "vieritys vetämällä". Valitse työkalu komponenttimuokkaimessa - se on lapsi ChartToolset objekti puussa - ja asettaa sen ominaisuus `Shift` arvoon `ssRight`. Tämä on hiiren painike joka aktivoi vieritystoiminnan. Voidaan yhdistää myös muita avaimia `Shift` ominaisuuteen, jos halutaan.
230230
231231Koska sisäänrakennetut työkalut ovat pois päältä kun käytetään ChartToolset:a niin voidaan myös palauttaa zoomaus valmiudet. - Aivan sama tapa: lisää "Zoomaus vetämällä" ja aseta sen `Shift` ominaisuus arvoon `ssLeft`.
232232
233233Jos suoritat ohjelman nyt voit vierittää näkymää vaikka sinulla olisi vanha Lazarus versio.
234234
235235### Zoomaus historia
236236
237237Jos zoomata syvemmälle ja syvemmälle Mandelbrotin joukkoa voit mennä yhden tai useamman vaiheen takaisin tutkia yksityiskohtia, jotka eivät enää näy nykyisellä zoomaustasolla. Zoom-historia tallentaa kaikki ulottuvuudet, jotka kerran olivat aktiivisia läpi koko zoomaus- ja vieritysprosessissa.
238238
239239Käännösyksiköiden `TATypes` ja `TAChartUtils` tarjoavat luokan `TAChartExtentHistory` mikä sallii toteuttaa zoomaus historian. Koska tämä ei ole komponentti niin on käytettävä koodia. Se luodaan `FormCreate` ja tuhotaan `FormDestroy` tapahtumassa koska zoomaus historia tarvitaan koko ohjelman ajan:
240240
241241``` pascal
242242procedure TForm1.FormCreate(Sender: TObject);
243243begin
244244 PopulateColorSource;
245245 Chart1ColorMapseries1.ColorSource := ColorSource;
246246 // Tämä on uutta:
247247 ZoomHistory := TChartExtentHistory.Create;
248248 ZoomHistory.Capacity := 100;
249249 // Historia voi kaapata 100 kertaa, kunnes vanhin tieto katoaa
250250end;
251251
252252procedure TForm1.FormDestroy(Sender: TObject);
253253begin
254254 ZoomHistory.Free;
255255end;
256256```
257257
258258Aina zoomauksen tai vierityksessa tapahtuvat näkyvän näkymän muutokset kaaviossa lisätään historiaan. Aloitetaan zoomaus jossa käytetään ZoomDragTool:n tapahtumaa `AfterMouseUp` yksinkertaisuuden vuoksi. Olisi myös mahdollista käyttää `OnExtentChanged` tapahtumaa, mutta tässä on oltava varovainen jottaa ohittaa extent muutokset kun perutaan zoomaus (unzooming) - Tästä tarkemmin TAChart mukana olevassa *extent demo*:ssa.
259259
260260Huomaa, että extent jo on muuttunut, kun `AfterMouseUp` tapahtuma tulee. Näin ollen, lisätään historiaan kaavion `PrevLogicalExtent` - tämä on näkymä, joka oli aktiivinen ennen kuin extent:ä muutettiin:
261261
262262``` pascal
263263procedure TForm1.ChartToolset1ZoomDragTool1AfterMouseUp(ATool: TChartTool;
264264 APoint: TPoint);
265265begin
266266 ZoomHistory.Add(Chart1.PrevLogicalExtent);
267267end;
268268```
269269
270270Vieritys on vähän mutkikkaampi, koska siinä tapahtuu extent muutoksia liikuttaessa hiirtä. MouseUp hetkellä `PrevLogicalExtent` joka on aktiivisena vierityksen alkaessa on jo korvattu useita kertoja. Mutta ratkaisu on yksinkertainen: Tässä voidaan käyttää PanDragTool:n `OnAfterMouseDown` tapahtumaa.
271271
272272Olisi kiinnostavaa näyttää infopaneelissa myös montako tasoa on otettu muistiin. `TChartExtentHistory` on sitä vastaava ominaisuus `Count` . Joten, lisätään toinen teksti ("`LblHistoryCount`") on infopaneeliin ja muuttaa kaavion `OnExtentChanged` tapahtumaa lisäämällä seuraava rivi:
273273
274274``` pascal
275275 LblHistoryCount.Caption := Format('History count: %d', [ZoomHistory.Count]);
276276```
277277
278278Ja miten palautetaan zoomauksen edellinen taso? Lisäämällä yksi CharTTool lisää. Sen käyttöön ei ole mitään erityisiä vaatimuksia, joten otamme [[TAChart documentation|UserDefinedChartTool]]. Aseta sen `Shift` ominaisuus niin, että työkalu reagoi vain hiiren keskimmäisellä painikkeella. Ja `OnAfterMouseClick` tapahtumakäsittelijässä luetaan viimeinen kohde historiasta (`ZoomHistory.Pop`) ja litetään saatu extent suorakulmio kaavion `LogicalExtent` kohtaan joka säätää näkymän vastaavasti. Tieto poistetaan historiasta pinon lukemisen jälkeen. Historian tietojen määrän näyttö infopaneelissa päivittyy automaattisesti, koska tapahtuma `OnExtentChanged` tapahtuu. Huomaa, että meidän täytyy tarkistaa onko historiatiedot tyhjänä jolloin vältetään poikkeus.
279279
280280``` pascal
281281procedure TForm1.ChartToolset1UserDefinedTool1AfterMouseUp(ATool: TChartTool;
282282 APoint: TPoint);
283283begin
284284 if ZoomHistory.Count > 0 then
285285 Chart1.LogicalExtent := ZoomHistory.Pop;
286286end;
287287```
288288
289289Jos halutaan nopeasti palata alkuperäiseen näkymään (suurennuksella 1) voi vetää hiiren vasemmalla painikkeella muuhun suuntaan kuin ylhäältä vasemmalle ja alas oikealle tai vain klikata kaaviota. Koska käyttöön otettiin hiiren keskimmäinen painike zoomauksen perumiseen niin käyttöliittymä voi olla johdonmukaisempi, jos lisätään uusi [[TAChart documentation|UserDefinedChartTool]] ja luovuttaa sen `Shift` ominaisuutta `ssMiddle` ja `ssShift` - usein liitetään `SHIFT` -näppäin toimintaan jolloin tehdään jotain suurempaa, kuten isoja kirjaimia. Siksi yhdistelmä hiiren keskimmäinen näppäin (zoomauksen peruminen) ja`SHIFT` -näppäin näyttää alkuperäisen näkymän.
290290
291291Käyttäjän voi kuitenkin olla vaikeaa pitää mielessä kaikki keskeiset yhdistelmät. Siksi lisätään infopaneelin muutamia tekstejä, jossa annetaan ohjeita zoomaukseen, vierittämiseen ja zoomauksen perumiseen.
292292
293293Niin, tässä on lopputulos tästä opetusohjelma projektista. Pidä hauskaa!
294294
295295![](/wiki-images/0/02/Mandelbrot_final.png)
296296
297297## Lähdekoodi
298298
299299Tämän opetusohjelman lähdekoodi löytyy TAChart:n kansiosta *tutorial\mandelbrot*.
300300
301301### project1.lpr
302302
303303``` pascal
304304program mandelbrot;
305305
306306{$mode objfpc}{$H+}
307307
308308uses
309309 {$IFDEF UNIX}{$IFDEF UseCThreads}
310310 cthreads,
311311 {$ENDIF}{$ENDIF}
312312 Interfaces, // this includes the LCL widgetset
313313 Forms, main, tachartlazaruspkg
314314 { you can add units after this };
315315
316316{$R *.res}
317317
318318begin
319319 RequireDerivedFormResource := True;
320320 Application.Initialize;
321321 Application.CreateForm(TForm1, Form1);
322322 Application.Run;
323323end.
324324```
325325
326326### main.pas
327327
328328``` pascal
329329unit main;
330330
331331{$mode objfpc}{$H+}
332332
333333interface
334334
335335uses
336336 Classes, ExtCtrls, StdCtrls, SysUtils, TAGraph, TAFuncSeries,
337337 TASources, Forms, Controls, Graphics, Dialogs, TATypes, TATools, Types;
338338
339339type
340340
341341 { TForm1 }
342342
343343 TForm1 = class(TForm)
344344 Chart1: TChart;
345345 Chart1ColorMapSeries1: TColorMapSeries;
346346 ChartToolset1: TChartToolset;
347347 ChartToolset1PanDragTool1: TPanDragTool;
348348 ChartToolset1UserDefinedTool1: TUserDefinedTool;
349349 ChartToolset1UserDefinedTool2: TUserDefinedTool;
350350 ChartToolset1ZoomDragTool1: TZoomDragTool;
351351 ColorSource: TListChartSource;
352352 Label1: TLabel;
353353 Label2: TLabel;
354354 Label3: TLabel;
355355 Label4: TLabel;
356356 Label5: TLabel;
357357 Label6: TLabel;
358358 Label7: TLabel;
359359 Label8: TLabel;
360360 Label9: TLabel;
361361 LblMagnification: TLabel;
362362 LblHistoryCount: TLabel;
363363 Panel1: TPanel;
364364 Panel2: TPanel;
365365 Panel3: TPanel;
366366 procedure Chart1ColorMapSeries1Calculate(const AX, AY: Double;
367367 out AZ: Double);
368368 procedure Chart1ExtentChanged(ASender: TChart);
369369 procedure ChartToolset1PanDragTool1AfterMouseDown(ATool: TChartTool;
370370 APoint: TPoint);
371371 procedure ChartToolset1UserDefinedTool1AfterMouseUp(ATool: TChartTool;
372372 APoint: TPoint);
373373 procedure ChartToolset1UserDefinedTool2AfterMouseUp(ATool: TChartTool;
374374 APoint: TPoint);
375375 procedure ChartToolset1ZoomDragTool1AfterMouseUp(ATool: TChartTool;
376376 APoint: TPoint);
377377 procedure FormCreate(Sender: TObject);
378378 procedure FormDestroy(Sender: TObject);
379379 private
380380 ZoomHistory: TChartExtentHistory;
381381 procedure PopulateColorSource;
382382 end;
383383
384384var
385385 Form1: TForm1;
386386
387387implementation
388388
389389{$R *.lfm}
390390
391391uses
392392 StrUtils,
393393 TAChartUtils, TAGeometry;
394394
395395const
396396 MANDELBROT_NUM_ITERATIONS = 100;
397397 MANDELBROT_ESCAPE_RADIUS = 2.0;
398398 MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS);
399399
400400function InMandelBrotSet(
401401 AC: TDoublePoint; out AIterations: Integer; out AZ: TDoublePoint): Boolean;
402402var
403403 j: Integer;
404404begin
405405 AIterations := 0;
406406 AZ := DoublePoint(0.0, 0.0);
407407 for j := 0 to MANDELBROT_NUM_ITERATIONS - 1 do begin
408408 AZ := DoublePoint(
409409 Sqr(AZ.X) - Sqr(AZ.Y) + AC.X,
410410 2 * AZ.X * AZ.Y + AC.Y);
411411 if Sqr(AZ.X) + Sqr(AZ.Y) > MANDELBROT_LIMIT then
412412 // point did escape --> AC is not in Mandelbrot set
413413 exit(false);
414414 AIterations += 1;
415415 end;
416416 Result := true;
417417end;
418418
419419{ TForm1 }
420420
421421procedure TForm1.FormCreate(Sender:TObject);
422422begin
423423 PopulateColorSource;
424424 ZoomHistory := TChartExtentHistory.Create;
425425 ZoomHistory.Capacity := 100;
426426end;
427427
428428procedure TForm1.FormDestroy(Sender: TObject);
429429begin
430430 ZoomHistory.Free;
431431end;
432432
433433procedure TForm1.Chart1ColorMapSeries1Calculate(
434434 const AX, AY: Double; out AZ: Double);
435435var
436436 iterations: Integer;
437437 z: TDoublePoint;
438438begin
439439 if InMandelBrotSet(DoublePoint(AX, AY), iterations, z) then
440440 AZ := -1
441441 // or - as a solution to the "homework" exercise:
442442 // AZ := sqrt(sqr(z.x) + sqr(z.y)) / MANDELBROT_ESCAPE_RADIUS
443443 else
444444 AZ := iterations / MANDELBROT_NUM_ITERATIONS;
445445end;
446446
447447procedure TForm1.Chart1ExtentChanged(ASender: TChart);
448448var
449449 cex, fex: TDoubleRect;
450450 factor: Double;
451451begin
452452 cex := ASender.CurrentExtent;
453453 fex := ASender.GetFullExtent;
454454 if cex.b.x = cex.a.x then exit;
455455
456456 factor := (fex.b.x - fex.a.x) / (cex.b.x - cex.a.x);
457457 LblMagnification.Caption :=
458458 'Magnification: ' + Format(IfThen(factor > 1e6, '%.0e', '%0.g'), [factor]);
459459 LblHistoryCount.Caption := Format('History count: %d', [ZoomHistory.Count]);
460460end;
461461
462462procedure TForm1.ChartToolset1PanDragTool1AfterMouseDown(
463463 ATool: TChartTool; APoint: TPoint);
464464begin
465465 Unused(ATool, APoint);
466466 ZoomHistory.Add(Chart1.PrevLogicalExtent);
467467end;
468468
469469procedure TForm1.ChartToolset1UserDefinedTool1AfterMouseUp(
470470 ATool: TChartTool; APoint: TPoint);
471471begin
472472 Unused(ATool, APoint);
473473 if ZoomHistory.Count > 0 then
474474 Chart1.LogicalExtent := ZoomHistory.Pop;
475475end;
476476
477477procedure TForm1.ChartToolset1UserDefinedTool2AfterMouseUp(
478478 ATool: TChartTool; APoint: TPoint);
479479begin
480480 Unused(ATool, APoint);
481481 Chart1.ZoomFull;
482482end;
483483
484484procedure TForm1.ChartToolset1ZoomDragTool1AfterMouseUp(
485485 ATool: TChartTool; APoint: TPoint);
486486begin
487487 Unused(ATool, APoint);
488488 ZoomHistory.Add(Chart1.PrevLogicalExtent);
489489end;
490490
491491procedure TForm1.PopulateColorSource;
492492const
493493 DUMMY = 0.0;
494494begin
495495 with ColorSource do begin
496496 Clear;
497497 Add(-1.0, DUMMY, '', clBlack);
498498 Add( 0.0, DUMMY, '', clBlue);
499499 Add( 0.3, DUMMY, '', clRed);
500500 Add( 1.0, DUMMY, '', clYellow);
501501 end;
502502end;
503503
504504end.
505505```
506506
507507### main.lfm
508508
509-``` pascal
509+``` lfm
510510object Form1: TForm1
511511 Left = 326
512512 Height = 285
513513 Top = 155
514514 Width = 468
515515 Caption = 'Form1'
516516 ClientHeight = 285
517517 ClientWidth = 468
518518 OnCreate = FormCreate
519519 OnDestroy = FormDestroy
520520 LCLVersion = '1.1'
521521 object Chart1: TChart
522522 Left = 4
523523 Height = 277
524524 Top = 4
525525 Width = 288
526526 AxisList = <
527527 item
528528 Visible = False
529529 Minors = <>
530530 Title.LabelFont.Orientation = 900
531531 end
532532 item
533533 Visible = False
534534 Alignment = calBottom
535535 Minors = <>
536536 end>
537537 Extent.UseXMax = True
538538 Extent.UseXMin = True
539539 Extent.UseYMax = True
540540 Extent.UseYMin = True
541541 Extent.XMax = 0.8
542542 Extent.XMin = -2.2
543543 Extent.YMax = 1.5
544544 Extent.YMin = -1.5
545545 Foot.Brush.Color = clBtnFace
546546 Foot.Font.Color = clBlue
547547 Proportional = True
548548 Title.Brush.Color = clBtnFace
549549 Title.Font.Color = clBlue
550550 Title.Text.Strings = (
551551 'TAChart'
552552 )
553553 Toolset = ChartToolset1
554554 OnExtentChanged = Chart1ExtentChanged
555555 Align = alClient
556556 BorderSpacing.Around = 4
557557 DoubleBuffered = True
558558 ParentColor = False
559559 object Chart1ColorMapSeries1: TColorMapSeries
560560 ColorSource = ColorSource
561561 Interpolate = True
562562 OnCalculate = Chart1ColorMapSeries1Calculate
563563 StepX = 1
564564 StepY = 1
565565 end
566566 end
567567 object Panel1: TPanel
568568 Left = 296
569569 Height = 285
570570 Top = 0
571571 Width = 172
572572 Align = alRight
573573 BevelOuter = bvNone
574574 ClientHeight = 285
575575 ClientWidth = 172
576576 TabOrder = 1
577577 object Panel2: TPanel
578578 Left = 0
579579 Height = 213
580580 Top = 72
581581 Width = 172
582582 Align = alClient
583583 BevelOuter = bvNone
584584 ClientHeight = 213
585585 ClientWidth = 172
586586 TabOrder = 0
587587 object Label2: TLabel
588588 Left = 6
589589 Height = 13
590590 Top = 8
591591 Width = 69
592592 Caption = 'Instructions'
593593 Font.Style = [fsBold]
594594 ParentColor = False
595595 ParentFont = False
596596 end
597597 object Label1: TLabel
598598 Left = 6
599599 Height = 13
600600 Top = 37
601601 Width = 45
602602 Caption = 'Left-drag'
603603 Font.Style = [fsItalic]
604604 ParentColor = False
605605 ParentFont = False
606606 end
607607 object Label3: TLabel
608608 Left = 6
609609 Height = 13
610610 Top = 80
611611 Width = 53
612612 Caption = 'Middle-click'
613613 Font.Style = [fsItalic]
614614 ParentColor = False
615615 ParentFont = False
616616 end
617617 object Label4: TLabel
618618 Left = 6
619619 Height = 13
620620 Top = 120
621621 Width = 97
622622 Caption = 'Middle-click w/SHIFT'
623623 Font.Style = [fsItalic]
624624 ParentColor = False
625625 ParentFont = False
626626 end
627627 object Label5: TLabel
628628 Left = 6
629629 Height = 13
630630 Top = 161
631631 Width = 51
632632 Caption = 'Right-drag'
633633 Font.Style = [fsItalic]
634634 ParentColor = False
635635 ParentFont = False
636636 end
637637 object Label6: TLabel
638638 Left = 19
639639 Height = 13
640640 Top = 56
641641 Width = 25
642642 Caption = 'zoom'
643643 ParentColor = False
644644 end
645645 object Label7: TLabel
646646 Left = 22
647647 Height = 13
648648 Top = 96
649649 Width = 81
650650 Caption = 'unzoom (history)'
651651 ParentColor = False
652652 end
653653 object Label8: TLabel
654654 Left = 19
655655 Height = 13
656656 Top = 136
657657 Width = 54
658658 Caption = 'full unzoom'
659659 ParentColor = False
660660 end
661661 object Label9: TLabel
662662 Left = 19
663663 Height = 13
664664 Top = 177
665665 Width = 18
666666 Caption = 'pan'
667667 ParentColor = False
668668 end
669669 end
670670 object Panel3: TPanel
671671 Left = 0
672672 Height = 72
673673 Top = 0
674674 Width = 172
675675 Align = alTop
676676 BevelOuter = bvNone
677677 ClientHeight = 72
678678 ClientWidth = 172
679679 TabOrder = 1
680680 object LblMagnification: TLabel
681681 Left = 6
682682 Height = 13
683683 Top = 8
684684 Width = 67
685685 Caption = 'Magnification:'
686686 ParentColor = False
687687 end
688688 object LblHistoryCount: TLabel
689689 Left = 6
690690 Height = 13
691691 Top = 29
692692 Width = 68
693693 Caption = 'History count:'
694694 ParentColor = False
695695 end
696696 end
697697 end
698698 object ColorSource: TListChartSource
699699 left = 115
700700 top = 57
701701 end
702702 object ChartToolset1: TChartToolset
703703 left = 115
704704 top = 120
705705 object ChartToolset1ZoomDragTool1: TZoomDragTool
706706 Shift = [ssLeft]
707707 OnAfterMouseUp = ChartToolset1ZoomDragTool1AfterMouseUp
708708 end
709709 object ChartToolset1PanDragTool1: TPanDragTool
710710 Shift = [ssRight]
711711 OnAfterMouseDown = ChartToolset1PanDragTool1AfterMouseDown
712712 end
713713 object ChartToolset1UserDefinedTool1: TUserDefinedTool
714714 Shift = [ssMiddle]
715715 OnAfterMouseUp = ChartToolset1UserDefinedTool1AfterMouseUp
716716 end
717717 object ChartToolset1UserDefinedTool2: TUserDefinedTool
718718 Shift = [ssShift, ssMiddle]
719719 OnAfterMouseUp = ChartToolset1UserDefinedTool2AfterMouseUp
720720 end
721721 end
722722end
723723```
724724
725725## Samankaltaiset oppimateriaalit
726726
727727- [[TAChart Tutorial: Getting started/fi|TAChart opas: Aloitus opas]]: Ensiaskeleet TAChart-kaaviokomponentilla
728728- [[TAChart Tutorial: Chart Tools]]: johdatus kaaviotyökaluihin (chart tools)
729729- [[TAChart Tutorial: Function Series/fi|TAChart opas: Funktiokuvaaja]]: esittelee `TFuncSeries` joka seuraa samanlainen käsite kuin `TColorMapSeries`
730730
731731---
732732*From the Free Pascal wiki, page "TAChart Tutorial: ColorMapSeries, Zooming/fi", as it stood on 2020-02-28 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history