Sign in Join
Wiki copytemporary

TAChart Tutorial: ColorMapSeries, Zooming/fi: what changed

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

Title: TAChart Tutorial: ColorMapSeries, Zooming/fi

OldNewLine
1+## Johdanto
2+
3+![](/wiki-images/0/02/Mandelbrot_final.png)
4+
5+["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ä.
6+
7+## Värikarttakuvaajan (TColormapSeries) käyttö
8+
9+Mikä 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.
10+
11+Vä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]] .
12+
13+Toinen "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ä.
14+
15+Valmis aloittamaan?
16+
17+Luo 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.
18+
19+![](/wiki-images/3/32/Madelbrot_ColorMapSeries.png)
20+
21+## Värikarttaan tutustuminen
22+
23+Jotta 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.
24+
25+Aluksi kirjoitetaan ColorMapSeries:n tapahtuman käsittelijä `OnCalculate`. Tämä on helppoa, koska halutaan vain yksinkertainen lineaarinen gradientti eli liukuvärjäys:
26+
27+``` pascal
28+procedure TForm1.Chart1ColorMapSeries1Calculate(const AX, AY: Double;
29+ out AZ: Double);
30+var
31+ ext: TDoubleRect; // unit TAChartUtils.pas
32+begin
33+ ext := Chart1.GetFullExtent;
34+ AZ := (AX - ext.a.x) /(ext.b.x - ext.a.x);
35+end;
36+```
37+
38+Jotta 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.
39+
40+Lopuksi 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`.
41+
42+Likuvä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.
43+
44+``` pascal
45+procedure TForm1.FormCreate(Sender: TObject);
46+begin
47+ PopulateColorSource;
48+end;
49+
50+procedure TForm1.PopulateColorSource;
51+const
52+ DUMMY = 0.0;
53+begin
54+ with ColorSource do begin
55+ Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen
56+ Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen
57+ end;
58+end;
59+```
60+
61+Johtuen `TListChartSource.Add` syntaksista täytyy antaa arvoja *y*-koordinaatille ja marks tekstille, käytetään siihen vakiota `DUMMY` ja tyhjää merkkijonoa koska niitä tarvita.
62+
63+Ajetaan 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 ...
64+
65+![](/wiki-images/5/52/Madelbrot_FirstGradient.png) ![](/wiki-images/f/fc/Mandelbrot_TwoGradients.png)
66+
67+Mennää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.
68+
69+``` pascal
70+procedure TForm1.PopulateColorSource;
71+const
72+ DUMMY = 0.0;
73+begin
74+ with ColorSource do begin
75+ Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen
76+ Add(0.3, DUMMY, '', clRed); // 0.3 --> punainen
77+ Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen
78+ end;
79+end;
80+```
81+
82+## Mandelbrotin joukko
83+
84+Joten 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.
85+
86+Niin 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.
87+
88+### Laskeminen
89+
90+Paras 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>).
91+
92+1. Aloita liittämällä c toiseen pisteeseen z = (z<sub>x</sub>, z<sub>y</sub>) = (c<sub>x</sub>, c<sub>y</sub>).
93+2. 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.)
94+3. 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>)
95+4. Nyt otetaan tämä tulos ja laitetaan se vaiheen 2 laskuun jälleen uutena z:n arvona
96+5. 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ää:
97+ - ![](/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.
98+ - 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ä.
99+
100+Vaikka 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.
101+
102+``` pascal
103+const
104+ MANDELBROT_NUM_ITERATIONS = 100;
105+ MANDELBROT_ESCAPE_RADIUS = 2.0;
106+ MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS);
107+
108+function InMandelbrotSet(c:TDoublePoint; out Iterations:Integer; out z: TDoublePoint): Boolean;
109+var
110+ j: Integer;
111+begin
112+ Iterations := 0;
113+ z := DoublePoint(0.0, 0.0); // unit TAGeometry.pas
114+ for j:=0 to MANDELBROT_NUM_ITERATIONS-1 do begin
115+ z := DoublePoint(
116+ sqr(z.X) - sqr(z.Y) + c.X,
117+ 2 * z.X * z.Y + c.Y
118+ );
119+ if sqr(z.X) + sqr(z.Y) > MANDELBROT_LIMIT then begin
120+ Result := false;
121+ // point did escape --> c ei kuulu Mandelbrotin joukkoon
122+ exit;
123+ end;
124+ inc(Iterations);
125+ end;
126+ Result := true;
127+end;
128+```
129+
130+### Piirtäminen
131+
132+Nyt 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.
133+
134+``` pascal
135+procedure TForm1.PopulateColorSource;
136+const
137+ DUMMY = 0.0;
138+begin
139+ with ColorSource do begin
140+ Clear;
141+ Add(-1.0, DUMMY, '', clBlack); // -1.0 --> musta
142+ Add(0.0, DUMMY, '', clBlue); // 0.0 --> sininen
143+ Add(0.3, DUMMY, '', clRed); // 0.3 --> punainen
144+ Add(1.0, DUMMY, '', clYellow); // 1.0 --> keltainen
145+ end;
146+end;
147+
148+procedure TForm1.Chart1ColorMapSeries1Calculate(const AX, AY: Double;
149+ out AZ: Double);
150+var
151+ iterations: Integer;
152+ z: TDoublePoint;
153+begin
154+ if InMandelBrotSet(DoublePoint(AX, AY), iterations, z) then
155+ AZ := -1
156+ else
157+ AZ := iterations / MANDELBROT_NUM_ITERATIONS;
158+end;
159+```
160+
161+Ja se, mikä on tämän tuloksena - katso vasen kuva:
162+
163+![](/wiki-images/e/eb/Madelbrot_FirstChart.png) ![](/wiki-images/9/9e/Mandelbrot_SecondChart.png)
164+
165+Erittäin kiva. Mutta kuten tavallista niin ensimmäinen tulos ei ole vielä paras mahdollinen. Tässä kaksi kohtaa, joita voidaan parantaa:
166+
167+- 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.
168+
169+- 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.
170+
171+Tulos 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.
172+
173+Ennen 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.
174+
175+## Zoomaus ja vieritys
176+
177+Johdannossa 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.
178+
179+### Sisäänrakennettu zoomaus
180+
181+`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.
182+
183+![](/wiki-images/2/23/Mandelbrot_Zooming.png) ![](/wiki-images/f/f4/Mandelbrot_ZoomingResult.png) ![](/wiki-images/3/34/Mandelbrot_DeepZoom.png)
184+
185+Tietenkin 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`.
186+
187+Mutta 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`.
188+
189+### Extents
190+
191+Miten 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.
192+
193+On 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).
194+
195+Milloin 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`.
196+
197+``` pascal
198+procedure TForm1.Chart1ExtentChanged(ASender: TChart);
199+var
200+ cex, fex: TDoubleRect;
201+ factor: double;
202+begin
203+ cex := Chart1.CurrentExtent;
204+ fex := Chart1.GetFullExtent;
205+ if cex.b.x = cex.a.x then exit;
206+
207+ factor := (fex.b.x - fex.a.x) / (cex.b.x - cex.a.x);
208+ if factor > 1e6 then
209+ LblMagnification.Caption := Format('Magnification: %.0e', [factor])
210+ else
211+ LblMagnification.Caption := Format('Magnification: %0.n', [factor]);
212+end;
213+```
214+
215+![](/wiki-images/2/25/Mandelbrot_ExtremeMag.png)
216+
217+Tä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.
218+
219+### Zoomaus kohti ääretöntä ...
220+
221+Kokeillaan 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 ...
222+
223+### Kaavion muokkaustyökalujen käyttö
224+
225+Jos 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]].
226+
227+Tä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.
228+
229+![](/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.
230+
231+Koska 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`.
232+
233+Jos suoritat ohjelman nyt voit vierittää näkymää vaikka sinulla olisi vanha Lazarus versio.
234+
235+### Zoomaus historia
236+
237+Jos 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.
238+
239+Kää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:
240+
241+``` pascal
242+procedure TForm1.FormCreate(Sender: TObject);
243+begin
244+ PopulateColorSource;
245+ Chart1ColorMapseries1.ColorSource := ColorSource;
246+ // Tämä on uutta:
247+ ZoomHistory := TChartExtentHistory.Create;
248+ ZoomHistory.Capacity := 100;
249+ // Historia voi kaapata 100 kertaa, kunnes vanhin tieto katoaa
250+end;
251+
252+procedure TForm1.FormDestroy(Sender: TObject);
253+begin
254+ ZoomHistory.Free;
255+end;
256+```
257+
258+Aina 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.
259+
260+Huomaa, 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:
261+
262+``` pascal
263+procedure TForm1.ChartToolset1ZoomDragTool1AfterMouseUp(ATool: TChartTool;
264+ APoint: TPoint);
265+begin
266+ ZoomHistory.Add(Chart1.PrevLogicalExtent);
267+end;
268+```
269+
270+Vieritys 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.
271+
272+Olisi 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:
273+
274+``` pascal
275+ LblHistoryCount.Caption := Format('History count: %d', [ZoomHistory.Count]);
276+```
277+
278+Ja 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.
279+
280+``` pascal
281+procedure TForm1.ChartToolset1UserDefinedTool1AfterMouseUp(ATool: TChartTool;
282+ APoint: TPoint);
283+begin
284+ if ZoomHistory.Count > 0 then
285+ Chart1.LogicalExtent := ZoomHistory.Pop;
286+end;
287+```
288+
289+Jos 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.
290+
291+Kä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.
292+
293+Niin, tässä on lopputulos tästä opetusohjelma projektista. Pidä hauskaa!
294+
295+![](/wiki-images/0/02/Mandelbrot_final.png)
296+
297+## Lähdekoodi
298+
299+Tämän opetusohjelman lähdekoodi löytyy TAChart:n kansiosta *tutorial\mandelbrot*.
300+
301+### project1.lpr
302+
303+``` pascal
304+program mandelbrot;
305+
306+{$mode objfpc}{$H+}
307+
308+uses
309+ {$IFDEF UNIX}{$IFDEF UseCThreads}
310+ cthreads,
311+ {$ENDIF}{$ENDIF}
312+ Interfaces, // this includes the LCL widgetset
313+ Forms, main, tachartlazaruspkg
314+ { you can add units after this };
315+
316+{$R *.res}
317+
318+begin
319+ RequireDerivedFormResource := True;
320+ Application.Initialize;
321+ Application.CreateForm(TForm1, Form1);
322+ Application.Run;
323+end.
324+```
325+
326+### main.pas
327+
328+``` pascal
329+unit main;
330+
331+{$mode objfpc}{$H+}
332+
333+interface
334+
335+uses
336+ Classes, ExtCtrls, StdCtrls, SysUtils, TAGraph, TAFuncSeries,
337+ TASources, Forms, Controls, Graphics, Dialogs, TATypes, TATools, Types;
338+
339+type
340+
341+ { TForm1 }
342+
343+ TForm1 = class(TForm)
344+ Chart1: TChart;
345+ Chart1ColorMapSeries1: TColorMapSeries;
346+ ChartToolset1: TChartToolset;
347+ ChartToolset1PanDragTool1: TPanDragTool;
348+ ChartToolset1UserDefinedTool1: TUserDefinedTool;
349+ ChartToolset1UserDefinedTool2: TUserDefinedTool;
350+ ChartToolset1ZoomDragTool1: TZoomDragTool;
351+ ColorSource: TListChartSource;
352+ Label1: TLabel;
353+ Label2: TLabel;
354+ Label3: TLabel;
355+ Label4: TLabel;
356+ Label5: TLabel;
357+ Label6: TLabel;
358+ Label7: TLabel;
359+ Label8: TLabel;
360+ Label9: TLabel;
361+ LblMagnification: TLabel;
362+ LblHistoryCount: TLabel;
363+ Panel1: TPanel;
364+ Panel2: TPanel;
365+ Panel3: TPanel;
366+ procedure Chart1ColorMapSeries1Calculate(const AX, AY: Double;
367+ out AZ: Double);
368+ procedure Chart1ExtentChanged(ASender: TChart);
369+ procedure ChartToolset1PanDragTool1AfterMouseDown(ATool: TChartTool;
370+ APoint: TPoint);
371+ procedure ChartToolset1UserDefinedTool1AfterMouseUp(ATool: TChartTool;
372+ APoint: TPoint);
373+ procedure ChartToolset1UserDefinedTool2AfterMouseUp(ATool: TChartTool;
374+ APoint: TPoint);
375+ procedure ChartToolset1ZoomDragTool1AfterMouseUp(ATool: TChartTool;
376+ APoint: TPoint);
377+ procedure FormCreate(Sender: TObject);
378+ procedure FormDestroy(Sender: TObject);
379+ private
380+ ZoomHistory: TChartExtentHistory;
381+ procedure PopulateColorSource;
382+ end;
383+
384+var
385+ Form1: TForm1;
386+
387+implementation
388+
389+{$R *.lfm}
390+
391+uses
392+ StrUtils,
393+ TAChartUtils, TAGeometry;
394+
395+const
396+ MANDELBROT_NUM_ITERATIONS = 100;
397+ MANDELBROT_ESCAPE_RADIUS = 2.0;
398+ MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS);
399+
400+function InMandelBrotSet(
401+ AC: TDoublePoint; out AIterations: Integer; out AZ: TDoublePoint): Boolean;
402+var
403+ j: Integer;
404+begin
405+ AIterations := 0;
406+ AZ := DoublePoint(0.0, 0.0);
407+ for j := 0 to MANDELBROT_NUM_ITERATIONS - 1 do begin
408+ AZ := DoublePoint(
409+ Sqr(AZ.X) - Sqr(AZ.Y) + AC.X,
410+ 2 * AZ.X * AZ.Y + AC.Y);
411+ if Sqr(AZ.X) + Sqr(AZ.Y) > MANDELBROT_LIMIT then
412+ // point did escape --> AC is not in Mandelbrot set
413+ exit(false);
414+ AIterations += 1;
415+ end;
416+ Result := true;
417+end;
418+
419+{ TForm1 }
420+
421+procedure TForm1.FormCreate(Sender:TObject);
422+begin
423+ PopulateColorSource;
424+ ZoomHistory := TChartExtentHistory.Create;
425+ ZoomHistory.Capacity := 100;
426+end;
427+
428+procedure TForm1.FormDestroy(Sender: TObject);
429+begin
430+ ZoomHistory.Free;
431+end;
432+
433+procedure TForm1.Chart1ColorMapSeries1Calculate(
434+ const AX, AY: Double; out AZ: Double);
435+var
436+ iterations: Integer;
437+ z: TDoublePoint;
438+begin
439+ if InMandelBrotSet(DoublePoint(AX, AY), iterations, z) then
440+ AZ := -1
441+ // or - as a solution to the "homework" exercise:
442+ // AZ := sqrt(sqr(z.x) + sqr(z.y)) / MANDELBROT_ESCAPE_RADIUS
443+ else
444+ AZ := iterations / MANDELBROT_NUM_ITERATIONS;
445+end;
446+
447+procedure TForm1.Chart1ExtentChanged(ASender: TChart);
448+var
449+ cex, fex: TDoubleRect;
450+ factor: Double;
451+begin
452+ cex := ASender.CurrentExtent;
453+ fex := ASender.GetFullExtent;
454+ if cex.b.x = cex.a.x then exit;
455+
456+ factor := (fex.b.x - fex.a.x) / (cex.b.x - cex.a.x);
457+ LblMagnification.Caption :=
458+ 'Magnification: ' + Format(IfThen(factor > 1e6, '%.0e', '%0.g'), [factor]);
459+ LblHistoryCount.Caption := Format('History count: %d', [ZoomHistory.Count]);
460+end;
461+
462+procedure TForm1.ChartToolset1PanDragTool1AfterMouseDown(
463+ ATool: TChartTool; APoint: TPoint);
464+begin
465+ Unused(ATool, APoint);
466+ ZoomHistory.Add(Chart1.PrevLogicalExtent);
467+end;
468+
469+procedure TForm1.ChartToolset1UserDefinedTool1AfterMouseUp(
470+ ATool: TChartTool; APoint: TPoint);
471+begin
472+ Unused(ATool, APoint);
473+ if ZoomHistory.Count > 0 then
474+ Chart1.LogicalExtent := ZoomHistory.Pop;
475+end;
476+
477+procedure TForm1.ChartToolset1UserDefinedTool2AfterMouseUp(
478+ ATool: TChartTool; APoint: TPoint);
479+begin
480+ Unused(ATool, APoint);
481+ Chart1.ZoomFull;
482+end;
483+
484+procedure TForm1.ChartToolset1ZoomDragTool1AfterMouseUp(
485+ ATool: TChartTool; APoint: TPoint);
486+begin
487+ Unused(ATool, APoint);
488+ ZoomHistory.Add(Chart1.PrevLogicalExtent);
489+end;
490+
491+procedure TForm1.PopulateColorSource;
492+const
493+ DUMMY = 0.0;
494+begin
495+ with ColorSource do begin
496+ Clear;
497+ Add(-1.0, DUMMY, '', clBlack);
498+ Add( 0.0, DUMMY, '', clBlue);
499+ Add( 0.3, DUMMY, '', clRed);
500+ Add( 1.0, DUMMY, '', clYellow);
501+ end;
502+end;
503+
504+end.
505+```
506+
507+### main.lfm
508+
509+``` pascal
510+object Form1: TForm1
511+ Left = 326
512+ Height = 285
513+ Top = 155
514+ Width = 468
515+ Caption = 'Form1'
516+ ClientHeight = 285
517+ ClientWidth = 468
518+ OnCreate = FormCreate
519+ OnDestroy = FormDestroy
520+ LCLVersion = '1.1'
521+ object Chart1: TChart
522+ Left = 4
523+ Height = 277
524+ Top = 4
525+ Width = 288
526+ AxisList = <
527+ item
528+ Visible = False
529+ Minors = <>
530+ Title.LabelFont.Orientation = 900
531+ end
532+ item
533+ Visible = False
534+ Alignment = calBottom
535+ Minors = <>
536+ end>
537+ Extent.UseXMax = True
538+ Extent.UseXMin = True
539+ Extent.UseYMax = True
540+ Extent.UseYMin = True
541+ Extent.XMax = 0.8
542+ Extent.XMin = -2.2
543+ Extent.YMax = 1.5
544+ Extent.YMin = -1.5
545+ Foot.Brush.Color = clBtnFace
546+ Foot.Font.Color = clBlue
547+ Proportional = True
548+ Title.Brush.Color = clBtnFace
549+ Title.Font.Color = clBlue
550+ Title.Text.Strings = (
551+ 'TAChart'
552+ )
553+ Toolset = ChartToolset1
554+ OnExtentChanged = Chart1ExtentChanged
555+ Align = alClient
556+ BorderSpacing.Around = 4
557+ DoubleBuffered = True
558+ ParentColor = False
559+ object Chart1ColorMapSeries1: TColorMapSeries
560+ ColorSource = ColorSource
561+ Interpolate = True
562+ OnCalculate = Chart1ColorMapSeries1Calculate
563+ StepX = 1
564+ StepY = 1
565+ end
566+ end
567+ object Panel1: TPanel
568+ Left = 296
569+ Height = 285
570+ Top = 0
571+ Width = 172
572+ Align = alRight
573+ BevelOuter = bvNone
574+ ClientHeight = 285
575+ ClientWidth = 172
576+ TabOrder = 1
577+ object Panel2: TPanel
578+ Left = 0
579+ Height = 213
580+ Top = 72
581+ Width = 172
582+ Align = alClient
583+ BevelOuter = bvNone
584+ ClientHeight = 213
585+ ClientWidth = 172
586+ TabOrder = 0
587+ object Label2: TLabel
588+ Left = 6
589+ Height = 13
590+ Top = 8
591+ Width = 69
592+ Caption = 'Instructions'
593+ Font.Style = [fsBold]
594+ ParentColor = False
595+ ParentFont = False
596+ end
597+ object Label1: TLabel
598+ Left = 6
599+ Height = 13
600+ Top = 37
601+ Width = 45
602+ Caption = 'Left-drag'
603+ Font.Style = [fsItalic]
604+ ParentColor = False
605+ ParentFont = False
606+ end
607+ object Label3: TLabel
608+ Left = 6
609+ Height = 13
610+ Top = 80
611+ Width = 53
612+ Caption = 'Middle-click'
613+ Font.Style = [fsItalic]
614+ ParentColor = False
615+ ParentFont = False
616+ end
617+ object Label4: TLabel
618+ Left = 6
619+ Height = 13
620+ Top = 120
621+ Width = 97
622+ Caption = 'Middle-click w/SHIFT'
623+ Font.Style = [fsItalic]
624+ ParentColor = False
625+ ParentFont = False
626+ end
627+ object Label5: TLabel
628+ Left = 6
629+ Height = 13
630+ Top = 161
631+ Width = 51
632+ Caption = 'Right-drag'
633+ Font.Style = [fsItalic]
634+ ParentColor = False
635+ ParentFont = False
636+ end
637+ object Label6: TLabel
638+ Left = 19
639+ Height = 13
640+ Top = 56
641+ Width = 25
642+ Caption = 'zoom'
643+ ParentColor = False
644+ end
645+ object Label7: TLabel
646+ Left = 22
647+ Height = 13
648+ Top = 96
649+ Width = 81
650+ Caption = 'unzoom (history)'
651+ ParentColor = False
652+ end
653+ object Label8: TLabel
654+ Left = 19
655+ Height = 13
656+ Top = 136
657+ Width = 54
658+ Caption = 'full unzoom'
659+ ParentColor = False
660+ end
661+ object Label9: TLabel
662+ Left = 19
663+ Height = 13
664+ Top = 177
665+ Width = 18
666+ Caption = 'pan'
667+ ParentColor = False
668+ end
669+ end
670+ object Panel3: TPanel
671+ Left = 0
672+ Height = 72
673+ Top = 0
674+ Width = 172
675+ Align = alTop
676+ BevelOuter = bvNone
677+ ClientHeight = 72
678+ ClientWidth = 172
679+ TabOrder = 1
680+ object LblMagnification: TLabel
681+ Left = 6
682+ Height = 13
683+ Top = 8
684+ Width = 67
685+ Caption = 'Magnification:'
686+ ParentColor = False
687+ end
688+ object LblHistoryCount: TLabel
689+ Left = 6
690+ Height = 13
691+ Top = 29
692+ Width = 68
693+ Caption = 'History count:'
694+ ParentColor = False
695+ end
696+ end
697+ end
698+ object ColorSource: TListChartSource
699+ left = 115
700+ top = 57
701+ end
702+ object ChartToolset1: TChartToolset
703+ left = 115
704+ top = 120
705+ object ChartToolset1ZoomDragTool1: TZoomDragTool
706+ Shift = [ssLeft]
707+ OnAfterMouseUp = ChartToolset1ZoomDragTool1AfterMouseUp
708+ end
709+ object ChartToolset1PanDragTool1: TPanDragTool
710+ Shift = [ssRight]
711+ OnAfterMouseDown = ChartToolset1PanDragTool1AfterMouseDown
712+ end
713+ object ChartToolset1UserDefinedTool1: TUserDefinedTool
714+ Shift = [ssMiddle]
715+ OnAfterMouseUp = ChartToolset1UserDefinedTool1AfterMouseUp
716+ end
717+ object ChartToolset1UserDefinedTool2: TUserDefinedTool
718+ Shift = [ssShift, ssMiddle]
719+ OnAfterMouseUp = ChartToolset1UserDefinedTool2AfterMouseUp
720+ end
721+ end
722+end
723+```
724+
725+## Samankaltaiset oppimateriaalit
726+
727+- [[TAChart Tutorial: Getting started/fi|TAChart opas: Aloitus opas]]: Ensiaskeleet TAChart-kaaviokomponentilla
728+- [[TAChart Tutorial: Chart Tools]]: johdatus kaaviotyökaluihin (chart tools)
729+- [[TAChart Tutorial: Function Series/fi|TAChart opas: Funktiokuvaaja]]: esittelee `TFuncSeries` joka seuraa samanlainen käsite kuin `TColorMapSeries`
730+
731+---
732+*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