Compare commits

...

2 Commits

Author SHA1 Message Date
728342951a Done lektoriranje 2026-05-31 22:36:09 +02:00
b922122a1f tmp 2026-05-27 22:15:11 +02:00

View File

@@ -628,7 +628,7 @@ Dna je sestavljen iz dveh struktur (@dna_objekt). Zanimliv del, ki ga opazimo, j
#pagebreak()
Če pogledamo definicijo od `newDna` (@dna_funkcije) vidimo pretvorbo(cast) iz `Dna` v `uint8_t*` in sedaj se lahko enostavno sprehodimo čez objekt in spremenimo vrednosti.
Če pogledamo definicijo od `newDna` (@dna_funkcije), vidimo pretvorbo (cast) iz `Dna` v `uint8_t*` in sedaj se lahko enostavno sprehodimo čez objekt in spremenimo vrednosti.
#figure(caption: [Primer DNA funkcije])[
```cpp
@@ -651,10 +651,10 @@ Dna je sestavljen iz dveh struktur (@dna_objekt). Zanimliv del, ki ga opazimo, j
```
]<dna_funkcije>
Ostale funkcije so podobne najprej pretvorimo v `uint_8*` in nato:
- `makeChild` naključno kopiramo iz staršev
- `clone` naključno kopiramo iz starša in vstavljamo naključne vrednosti
- `mutate` pa sprecificirano število vrednosti spremenimo v naključne vrednosti
Ostale funkcije so podobne; najprej pretvorimo v `uint_8*` in nato:
- `makeChild` naključno kopiramo iz staršev,
- `clone` naključno kopiramo iz starša in vstavljamo naključne vrednosti,
- `mutate` pa sprecificirano število vrednosti spremenimo v naključne vrednosti.
@@ -668,7 +668,7 @@ Ostale funkcije so podobne najprej pretvorimo v `uint_8*` in nato:
caption: [Končna slika po vizualizaciji],
)
Je sestavljena iz treh razredov `Canvas`, `BackGround`, `Tree`(@razredi_vizualizacije). Tukaj Canvas je samo umesni razred ki postavi risanje na teksturo in nato pokliče BackGround in Tree
Je sestavljena iz treh razredov: `Canvas`, `BackGround`, `Tree` (@razredi_vizualizacije). Tukaj je Canvas samo vmesni razred, ki postavi risanje na teksturo in nato pokliče BackGround in Tree.
#figure(caption: [Razredi za vizualizacijo])[
#grid(
@@ -728,20 +728,20 @@ Je sestavljena iz treh razredov `Canvas`, `BackGround`, `Tree`(@razredi_vizualiz
=== Ozadje
Postopek izrisa ozadja je sestavljen iz 5 korakov
+ Nebo je narisano z pomočjo raylib funkcije `DrawRectangleGradientV`(@steps_nebo)
+ Nebo je narisano s pomočjo raylib funkcije `DrawRectangleGradientV` (@steps_nebo).
+ Če je noč, zvezde narišemo z naključnim semenom iz DNA ki se uporabi za pozicijo, in funkcijo `DrawTriangle` (@steps_zvezde)
+ Če je noč, zvezde narišemo z naključnim semenom iz DNA, ki se uporabi za pozicijo, in funkcijo `DrawTriangle` (@steps_zvezde).
+ Sonce in Luna so narisane z raylib funkcijo `DrawCircle` (@steps_sonce)
+ Sonce in luna sta narisana z raylib funkcijo `DrawCircle` (@steps_sonce).
+ Gore so bile težje za narisat odločil sem se da bom uporabil triangle strip, (@Triangle_Strip) @wiki_triangle_strip najprej se odlocimo iz koliko segmentov jo bomo narisali v aplikaciji uporabljamo 150 segmentov s tem imamo širino segmenta. Sedaj sledimo tem korakom:
+ Prvo točko postavimo v spodnjem levem kotu (0,0)
+ Za drugo točko si izberemo naključno številko za višino gore (0,80)
+ Naslednja točka je spet na telh samo zamaknjena za širino segmenta na desno(20,0)
+ Za naslednjo točko si zberemo naključno število za višino gore in zamaknjeno na desno od prejšne višine (20, 90)
+ Sedaj ponavljamo točko 3 in 4 dokler ne pridemo do desnega roba slike
+ Gore so bile težje za narisati, zato smo se odločili, da bomo uporabili triangle strip (@Triangle_Strip) @wiki_triangle_strip. Najprej smo se odločili, iz koliko segmentov jo bomo narisali v aplikaciji; uporabljamo 150 segmentov, s tem imamo širino segmenta. Sedaj sledimo tem korakom:
+ Prvo točko postavimo v spodnji levi kot (0,0).
+ Za drugo točko si izberemo naključno številko za višino gore (0,80).
+ Naslednja točka je spet na tleh, samo zamaknjena za širino segmenta na desno (20,0).
+ Za naslednjo točko si zberemo naključno število za višino gore in zamaknjeno na desno od prejšne višine (20, 90).
+ Sedaj ponavljamo točki 3 in 4, dokler ne pridemo do desnega roba slike.
+ Ponovimo korak 4 še dvakrat da dobimo gorovje (@steps_gora_5)
+ Ponovimo korak 4 še dvakrat, da dobimo gorovje (@steps_gora_5).
#block(breakable: false)[
#grid(
@@ -811,23 +811,23 @@ Postopek izrisa ozadja je sestavljen iz 5 korakov
#let da = `DrawArgs`
#let dn = `Branch`
Algoritem za izris drevesa je iterativni proceduralni generator. Za izdris uporabljamo strukturo #dn (@dna_objekt) in `std::list` (FIFO) #da (@razredi_vizualizacije)
Algoritem za izris drevesa je iterativni proceduralni generator. Za izris uporabljamo strukturo #dn (@dna_objekt) in `std::list` (FIFO) #da (@razredi_vizualizacije).
==== DNA Branch
Veja je struktura ki vsebuje podatke o:
Veja je struktura, ki vsebuje podatke o:
- Začetni barvi (`colorX`) [0, 255]
- Spremembi barve (`colorX_change`) za koliko se barva spremeni čez dolžino veje [0, 255]
- Variaciji zečetne barve (`colorVar`) za koliko se lahko naključno spremeni začetna barva [-15, -15]
- Začetna debelina (`size`) [2, 20]
- Debelina glede na starša (`sizeParent`) [0.0, 1.0]
- Debelina glede na globino (`sizeLevel`) iz @table_glob_data procent koliko je podoben predefinirani velikosti [0.0, 1.0]
- Sprememba debeline (`sizeChange`) za končna debelina veje [-5, 5]
- Variacija debeline (`sizeVar`) za koliko se lahko naključno spremeni začetna debelina [-5, 5]
- Dolžina (`length`) veje [0.5, 1.3]
- Variacija dolžine (`lengthVar`) za koliko se lahko nakključno spremeni dolžina veje [-0.15, 0.15]
- Stevilo otrokov (`branchCount`) koliko vej bo nadaljevalo [2, 3]
- Variacija kota med vejami (`branchAngleVar`) naključna variacija kota med vejami za to da ni enakomerno razporejeno [0, 20]
- začetni barvi (`colorX`) [0, 255],
- spremembi barve (`colorX_change`), za koliko se barva spremeni čez dolžino veje [0, 255],
- variaciji začetne barve (`colorVar`), za koliko se lahko naključno spremeni začetna barva [-15, -15],
- začetni debelini (`size`) [2, 20],
- debelini glede na starša (`sizeParent`) [0.0, 1.0],
- debelini glede na globino (`sizeLevel`); iz @table_glob_data procent, koliko je podoben predefinirani velikosti [0.0, 1.0],
- spremembi debeline (`sizeChange`) za končno debelino veje [-5, 5],
- variaciji debeline (`sizeVar`), za koliko se lahko naključno spremeni začetna debelina [-5, 5],
- dolžini (`length`) veje [0.5, 1.3],
- variaciji dolžine (`lengthVar`), za koliko se lahko naključno spremeni dolžina veje [-0.15, 0.15],
- številu otroki (`branchCount`), koliko vej bo nadaljevalo [2, 3],
- variaciji kota med vejami (`branchAngleVar`) naključna variacija kota med vejami zato, da ni enakomerno razporejeno [0, 20].
#figure(caption: [Globalni podatki])[
#table(
@@ -844,7 +844,7 @@ Veja je struktura ki vsebuje podatke o:
// TODO: Dodaj slike za lazjo predstavo
==== Algoritem
Začnemo tako, da damo v list @prvi_drawArgs in ponavljamo naslednje postopke dokler imamo nekaj v listi
Začnemo tako, da damo v seznam, kar prikazuje @prvi_drawArgs, in ponavljamo naslednje postopke, dokler imamo nekaj v seznamu.
#figure(caption: [Prvi DrawArgs])[
```cpp
struct DrawArgs
@@ -856,11 +856,10 @@ Začnemo tako, da damo v list @prvi_drawArgs in ponavljamo naslednje postopke do
```
]<prvi_drawArgs>
+ Korak: Predpostavek
Da lahko narišemo drevo predvidevamo da imamo strukturo `Dna`
+ Korak: Predpostavek, da lahko narišemo drevo, predvidevamo, da imamo strukturo `DNA`
+ Korak: Priprava
Pridobimo `DrawArgs arg` in `Branch b`
```cpp
@@ -1019,7 +1018,7 @@ Začnemo tako, da damo v list @prvi_drawArgs in ponavljamo naslednje postopke do
=== Optimizacija izrisa
Sprava se je drevo izrisalo s pomočjo raylib funkcije `DrawLineEx`, drevo se je izrisevalo vsak okvir(frame). Kasneje smo hoteli dodali veje z spremenljivo debelino, najlažja rešitev ki smo se jo spomnili je bila da narišemo krogce z spremenljivim polmerom. To nas je prisililo da moramo narisati čez 55,000 krogov. Z raylib-ovo funkcijo `DrawCircleV` za risanje krogov, je applikacija začela zaostajati(lagged). To smo rešili tako da najprej drevo narišemo na teksturo, ki je zelo enostavna za izris. To je rešilo večino problemov občasno se je ševedno pojavil zaostanek(lag spoke), ki smo ga rešili tako da smo omejili število risalnih klicov na okvir in drevo narisali v parih okvirih.
Sprva se je drevo izrisalo s pomočjo raylib funkcije `DrawLineEx`, drevo se je izrisovalo vsak okvir (frame). Kasneje smo hoteli dodati veje s spremenljivo debelino, najlažja rešitev, ki smo se jo spomnili, je bila, da narišemo krogce s spremenljivim polmerom. To nas je prisililo, da moramo narisati čez 55000 krogov. Z raylibovo funkcijo `DrawCircleV` za risanje krogov je applikacija začela zaostajati (lagged). To smo rešili tako, da najprej drevo narišemo na teksturo, ki je zelo enostavna za izris. To je rešilo večino problemov, občasno se je še vedno pojavil zaostanek (lag spike), ki smo ga rešili tako, da smo omejili število risalnih klicev na okvir in drevo narisali v par okvirjih.
#align(center)[
#figure(caption: [Optimizacije izrisa])[
@@ -1030,10 +1029,10 @@ Sprava se je drevo izrisalo s pomočjo raylib funkcije `DrawLineEx`, drevo se je
[Optimizacija], [Povprečen ms/okvir], [Skupni čas izrisa slike], [Maks ms/okvir po zamenjavi slike], [FPS]
),
table.hline(),
[Izris z črtami], [2], [2], [3], [350],
[Izris z krogi vsak okvir], [100], [100], [100], [10],
[Izris z krogi v teksturo], [0.2], [100], [100], [5000],
[Izris z krogi v teksturo čez več okvirov], [0.2], [100], [14], [5000],
[Izris s črtami], [2], [2], [3], [350],
[Izris s krogi vsak okvir], [100], [100], [100], [10],
[Izris s krogi v teksturo], [0.2], [100], [100], [5000],
[Izris s krogi v teksturo čez več okvirjev], [0.2], [100], [14], [5000],
)
]
]
@@ -1041,7 +1040,7 @@ Sprava se je drevo izrisalo s pomočjo raylib funkcije `DrawLineEx`, drevo se je
#pagebreak()
=== DNA manager optimizacija
Na zažetku (@dna_manager_v1) je DnaManager samo bil struktura kazalcev na `Dna`, s tem imamo problem da nemoremo shraniti kazalcev v datoteko. Smo spremenili na indekse (@dna_manager_v2), ki se dajo zapisati v datoteko, kasneje smo se spomnili da bi bilo dobro za predpomnilnik da so indeksi v queued sortirani. In med razhroscevanjem smo opazili da queued in showed delujeta kot premikajoči indeksi za queued, pred njim so stvari ki so že prikazane za njim pa so stvari, ki jih še moramo prikazati. Za to smo spremenili queued in showed v en indeks namesto list (@dna_manager_v3).
Na začetku (@dna_manager_v1) je bil DnaManager samo struktura kazalcev na `DNA`, s tem imamo problem, da ne moremo shraniti kazalcev v datoteko. Spremenili smo ga na indekse (@dna_manager_v2), ki se dajo zapisati v datoteko, kasneje pa smo se spomnili, da bi bilo dobro za predpomnilnik, da so indeksi v queued sortirani. Med razhroščevanjem smo opazili, da queued in showed delujeta kot premikajoči indeksi za queued: pred njim so stvari, ki so že prikazane, za njim pa so stvari, ki jih še moramo prikazati. Zato smo spremenili queued in showed v en indeks namesto list (@dna_manager_v3).
#align(center)[
#grid(
@@ -1097,24 +1096,24 @@ Na zažetku (@dna_manager_v1) je DnaManager samo bil struktura kazalcev na `Dna`
#pagebreak()
= PODOBNOST
Da smo lahko prikazali koliko so uporabniku slike všeč. Smo se odločili, da bomo izračunali podobnost med slikami, bolj ko so si slike podobne bolj so všeč uporabniku in obratno. Za to smo preučili sedem algoritmov.
Da smo lahko prikazali, koliko so uporabniku slike všeč, smo se odločili, da bomo izračunali podobnost med slikami. Bolj ko so si slike podobne, bolj so všeč uporabniku in obratno. Zato smo preučili sedem algoritmov.
== Opis algoritmov
=== Evklidska razdalja
Evklidska razdalja je najkrajša razdalja med dvema točkama v evklidskem prostoru, ki je najpogosteje uporabljen koncept razdalje v matematiki in fiziki. @wiki_euclidean_distance
Evklidska razdalja je najkrajša razdalja med dvema točkama v evklidskem prostoru, ki je najpogosteje uporabljen koncept razdalje v matematiki in fiziki @wiki_euclidean_distance.
==== Formula
Za dve točki p in q v n-dimenzionalnem prostoru se izračuna:
$ d(p, q) = sqrt(sum_(i=1)^n (q_i - p_i)^2) $
==== Normalizacija
Da normaliziramo Evklidsko razdaljo moramo deliti z najdaljšo možno razdaljo v prostoru:
Da normaliziramo Evklidsko razdaljo, moramo deliti z najdaljšo možno razdaljo v prostoru:
$ "maxDistance" = 255 sqrt(n) $
Normalizacija je nato:
$ "normalizedDistance" = frac(d(p, q), "maxDistance") $
=== Skalarni produkt
Skalarni produkt (tudi dot produkt ali notranji produkt) je operacija med dvema vektorjema v vektorskem prostoru, ki kot rezultat vrne skalar (realno število). @wiki_dot_product
Skalarni produkt (tudi dot produkt ali notranji produkt) je operacija med dvema vektorjema v vektorskem prostoru, ki kot rezultat vrne skalar (realno število) @wiki_dot_product.
==== Formula:
Za vektorja A in B v n-dimenzionalnem prostoru:
@@ -1133,22 +1132,22 @@ $
$
=== Kosinusna podobnost
Kosinusna podobnost je mera, ki se uporablja za določanje podobnosti dveh vektorjev, ne glede na njuno velikost. Izračuna kosinus kota med dvema vektorjema v n-dimenzionalnem prostoru. @wiki_cosine_similarity
Kosinusna podobnost je mera, ki se uporablja za določanje podobnosti dveh vektorjev ne glede na njuno velikost. Izračuna kosinus kota med dvema vektorjema v n-dimenzionalnem prostoru @wiki_cosine_similarity.
==== Formula:
$
"similarity" = frac(upright(bold(A)) op(dot) upright(bold(B)), ||upright(bold(A))|| ||upright(bold(B))||)
$
==== Variation
Variaciaja, ki jo bomo testirali je da najprej mapiramo vrednosti genov iz (0, 255) v (-127 to 128) in s tem razširimo izhodno območje.
==== Variacija
Variaciaja, ki jo bomo testirali, je, da najprej mapiramo vrednosti genov iz (0, 255) v (-127 to 128) in s tem razširimo izhodno območje.
=== Hammingova razdalja
Hammingova razdalja je koncept v matematiki in računalništvu, ki meri razliko med dvema zaporedjema enake dolžine. Najpogosteje se uporablja za nize znakov, binarne zaporedja (npr. bitne nize) ali DNA zaporedja. @wiki_hamming_distance
Hammingova razdalja je koncept v matematiki in računalništvu, ki meri razliko med dvema zaporedjema enake dolžine. Najpogosteje se uporablja za nize znakov, binarne zaporedja (npr. bitne nize) ali DNA zaporedja @wiki_hamming_distance.
=== Jaccardov indeks
Jaccardov indeks (ali Jaccardov koeficient podobnosti) je metrika, ki meri podobnost med dvema množicama. Izračuna se kot razmerje med velikostjo presečiška obeh množic in velikostjo njihove unije. @wiki_jaccard_index
Jaccardov indeks (ali Jaccardov koeficient podobnosti) je metrika, ki meri podobnost med dvema množicama. Izračuna se kot razmerje med velikostjo presečišča obeh množic in velikostjo njihove unije @wiki_jaccard_index.
==== Formula:
$
@@ -1156,9 +1155,9 @@ $
$
=== Levenshteinova razdalja
Levenshteinova razdalja (ali urejevalna razdalja) je metrika, ki meri razliko med dvema nizoma znakov. Določa najmanjše število urejevalnih operacij (vstavitev, izbris ali zamenjava znakov), potrebnih za pretvorbo enega niza v drugega. @wiki_levenshtein_distance
Levenshteinova razdalja (ali urejevalna razdalja) je metrika, ki meri razliko med dvema nizoma znakov. Določa najmanjše število urejevalnih operacij (vstavitev, izbris ali zamenjava znakov), potrebnih za pretvorbo enega niza v drugega @wiki_levenshtein_distance.
==== Formula
==== Formula:
#let head = "head"
#let tail = "tail"
#let lev = "lev"
@@ -1185,11 +1184,11 @@ head(x) is first character of x
=== Needleman-Wunschev algoritem
Needleman-Wunschov algoritem je algoritem, ki se uporablja v bioinformatiki za poravnavo beljakovinskih ali nukleotidnih zaporedij. Bil je ena prvih aplikacij dinamičnega programiranja za primerjavo bioloških zaporedij. Včasih se imenuje tudi algoritem optimalnega ujemanja in tehnika globalne poravnave. Needleman-Wunschov algoritem se še vedno široko uporablja za optimalno globalno poravnavo, zlasti kadar je kakovost globalne poravnave najpomembnejša. Algoritem dodeli oceno vsakemu možnemu poravnavanju, njegov namen pa je najti vsa možna poravnavanja z najvišjo oceno. @wiki_needlemanwunsch_algorithm
Needleman-Wunschev algoritem je algoritem, ki se uporablja v bioinformatiki za poravnavo beljakovinskih ali nukleotidnih zaporedij. Bil je ena prvih aplikacij dinamičnega programiranja za primerjavo bioloških zaporedij. Včasih se imenuje tudi algoritem optimalnega ujemanja in tehnika globalne poravnave. Needleman-Wunschov algoritem se še vedno široko uporablja za optimalno globalno poravnavo, zlasti kadar je kakovost globalne poravnave najpomembnejša. Algoritem dodeli oceno vsakemu možnemu poravnavanju, njegov namen pa je najti vsa možna poravnavanja z najvišjo oceno @wiki_needlemanwunsch_algorithm.
#pagebreak()
== Testiranje algoritmov
Testiranje je potekalo na večjih primerih evolucije. Spodaj je prikazani en primer rezultatov podobnosti in časa računanja podobnosti v mikrosecundah. Slike generacij so v prilogi.
Testiranje je potekalo na več primerih evolucije. Spodaj je prikazan en primer rezultatov podobnosti in časa računanja podobnosti v mikrosekundah. Slike generacij so v prilogi.
=== Testno okolje
Algoritmi so bili testirani na računalniku z AMD Ryzen 5 5500U procesorjem in 16 GB rama. Vsak algoritem je bil zagnan petkrat in podatki so povprečje rezultatov.
@@ -1243,7 +1242,7 @@ Algoritmi so bili testirani na računalniku z AMD Ryzen 5 5500U procesorjem in 1
)
#pagebreak()
=== Čas računanja podobnosti v us
=== Čas računanja podobnosti v μs
#align(center)[
#figure(caption: [Čas računanja podobnosti])[
#table(
@@ -1290,24 +1289,24 @@ Algoritmi so bili testirani na računalniku z AMD Ryzen 5 5500U procesorjem in 1
#pagebreak()
== Odločitev
Odločili smo se da bomo uporabili Hammingovo razdaljo, ker nam je všeč rezultat podobnosti, ker zače pri 0% nadaljuje proti 100% in kako enostavna je implementacija. Čas računanja podobnosti nismo upoštevali ker so vsi razen Levenshteinova razdalja bili manj kot 0.5 milisekunde in je to za nas dovolj hitro.
Odločili smo se, da bomo uporabili Hammingovo razdaljo, ker nam je všeč rezultat podobnosti, ker zače pri 0 % nadaljuje proti 100 % in implementacija je enostavna. Časa računanja podobnosti nismo upoštevali, ker so bili vsi razen Levenshteinove razdalje manj kot 0.5 milisekunde in je to za nas dovolj hitro.
Opazili ste da Jaccard indeks in Needleman-Wunsch algoritem manjakta v testiranju in to je zato ker:
Opaziti je, da Jaccarda indeks in Needleman-Wunschev algoritem manjakta v testiranju, in to je zato, ker:
- Jaccardov indeks ni primeren za nas, ker deluje na skupini unikatnih vrednosti kar mi nimamo, mi lahko imamo dve isti vrednosti ki predstavljata dva različni lastnosti slike. Zato tudi če bi dobili 100% ujemanje ne bi pomenilo da se sliki 100% ujemata.
- Needleman-Wunsch alogitem nam pa ne vrne nevtralne stevilke ki bi jo lahko uporabili za rezultat podobnosti.
- Jaccardov indeks ni primeren za nas, ker deluje na skupini unikatnih vrednosti, česar mi nimamo, ker imamo lahko dve isti vrednosti, ki predstavljata dve različni lastnosti slike. Zato tudi če bi dobili 100 %, ujemanje ne bi pomenilo, da se sliki 100 % ujemata.
- Nam Needleman-Wunschev alogitem ne vrne nevtralne številke, ki bi jo lahko uporabili za rezultat podobnosti.
#pagebreak()
= Google Play Store
Da lahko objavimo aplikacijo na Google Play Store potrebujemo Play Console razvijalski račun @web_google_play_console. Koraki za izdelavo računa so zelo enostavni, vpiši potrebne podatke, sprejmi razvojni sporazum, in plačaj registracijo. Naši problemi so se začeli z vnosom podatkov ni so hoteli sprejeti naše telefonske številke, ker ni so mogli preverit, ko smo pa sledili korakom za odstranjevaje težav, ki so večinoma samo bili počakajte en dan in poskusite ponovno, še vedno ni delovalo. Nato smo kontaktirali njihovo pomoč, ki so nam vrnili podoben odgovor da naj čakamo, po tem smo obupali in samo uporabili drugo telefonsko številko.
Da lahko objavimo aplikacijo na Google Play Store, potrebujemo Play Console razvijalski račun @web_google_play_console. Koraki za izdelavo računa so zelo enostavni: vpiši potrebne podatke, sprejmi razvojni sporazum in plačaj registracijo. Naši problemi so se začeli z vnosom podatkov, saj niso hoteli sprejeti naše telefonske številke, ker je niso mogli preveriti, ko pa smo sledili korakom za odstranjevaje težav, ki so bili večinoma samo _počakajte en dan in poskusite ponovno_, še vedno ni delovalo. Nato smo kontaktirali njihovo pomoč, ki so nam vrnili podoben odgovor, da naj čakamo. Po tem smo obupali in uporabili drugo telefonsko številko.
V naslednjih korakih moramo naložiti zapakirano aplikacijo, dodati opis applikacije, slike delovanja in politiko varstva osebnih podatkov (@privacy_policy). Po tem pa moramo spraviti aplikacijo čez notranje testiranje, ki je zelo ne specificirano, generalna ideja naj bi bila da potrebujemo 12 testerjev, ki naj bi uporabljali aplikacijo vsaj 12 dni nikjer pa ni omenjeno koliko časa na dan morajo uporabljati aplikacijo da se šteje. Par tednov smo poskušali z prijatelji ugotoviti kdaj postaneš aktiven samo smo brez uspeha. Nato smo se odločili da bi pogledali po internetu kako ta problem rešujejo ostali. Našli smo dve rešitvi. Prva zastonj rešitev, je nekaj forumov na spletu kjer ljudje objavljajo svoje aplikacije in ideja je da si med samo pomagajo s tem da testirajo drug od drugih aplikacije. Droga plačljiva rešitev za katero smo se mi odločili je da najamemo testerja za pribljižno 20€. Z testerjem smo se zmenili kaj potrebujemo in po izmenjavi potrebnih podatko je po dveh tednih aplikacija testirana in lahko nadaljuje na zadnji pregled pred objavo.
V naslednjih korakih moramo naložiti zapakirano aplikacijo, dodati opis applikacije, slike delovanja in politiko varstva osebnih podatkov (@privacy_policy). Po tem moramo spraviti aplikacijo čez notranje testiranje, ki je zelo nespecificirano. Generalna ideja naj bi bila, da potrebujemo 12 testerjev, ki naj bi uporabljali aplikacijo vsaj 12 dni, nikjer pa ni omenjeno, koliko časa na dan morajo uporabljati aplikacijo, da se šteje. Par tednov smo s prijatelji poskušali ugotoviti, kdaj postaneš aktiven, ampak smo bili brez uspeha. Nato smo se odločili, da bi pogledali po internetu, kako ta problem rešujejo ostali. Našli smo dve rešitvi. Prva zastonj rešitev je nekaj forumov na spletu, kjer ljudje objavljajo svoje aplikacije in ideja je, da si med sabo pomagajo s tem, da testirajo aplikacije drug drugega. Druga plačljiva, rešitev za katero smo se odločili, je, da najamemo testerja za pribljižno 20 €. S testerjem smo se zmenili, kaj potrebujemo, in po izmenjavi potrebnih podatkv je po dveh tednih aplikacija testirana in lahko nadaljuje na zadnji pregled pred objavo.
Ob zadnjem pregledu je postalo zelo naporno. Opis naše aplikacije je navdihnil opis aplikacije Tinder, saj sta aplikaciji konceptno zelo podobni (@zacetni_opis). Takrat so pri Googlu začeli natančno pregledovati aplikacijo, ker do takrat je bilo vsakič, ko smo poslali aplikacijo v pregled, vse odobreno do naslednjega dne, tokrat pa je trajalo nekaj tednov. Njihov odgovor je bil, da opis naše aplikacije ni primeren in krši pravila, čeprav je bil zelo podoben Tindrovemu. Pri tem smo ugotovili, da se je ekipa, ki je to pregledovala, vedla precej pristransko. V skladu z navodili, ki so nam jih poslali, smo popravili vse kršitve pravil. Tako se je ponovilo še nekajkrat, kar je skupaj trajalo skoraj štiri mesece. Zadnja verzija je (@koncni_opis).
Ob zadnjem pregledu je postalo zelo naporno. Opis naše aplikacije je navdihnil opis aplikacije Tinder, saj sta aplikaciji konceptno zelo podobni (@zacetni_opis). Takrat so pri Googlu začeli natančno pregledovati aplikacijo, ker do takrat je bilo vsakič, ko smo poslali aplikacijo v pregled, vse odobreno do naslednjega dne, tokrat pa je trajalo nekaj tednov. Njihov odgovor je bil, da opis naše aplikacije ni primeren in krši pravila, čeprav je bil zelo podoben Tindrovemu. Pri tem smo ugotovili, da se je ekipa, ki je to pregledovala, vedla precej pristransko. V skladu z navodili, ki so nam jih poslali, smo popravili vse kršitve pravil. Tako se je ponovilo še nekajkrat, kar je skupaj trajalo skoraj štiri mesece. Zadnja verzija je @koncni_opis.
Po vsem tem je aplikacija končno objavljena na Play Store @web_google_treender
Po vsem tem je aplikacija končno objavljena na Play Store @web_google_treender.
#figure(caption: [Začetni opis])[
@@ -1401,19 +1400,19 @@ This Privacy Policy is effective as of February 26, 2025. We reserve the right t
= UPORABNIŠKE IZKUŠNJE
Po tem ko smo objavili aplikacijo na Play Store smo prosili prijatelje in sodelavce, naj probajo aplikacijo. Med uporabo so naleteli na nekaj pričakovanih in nepričakovanih problemov.
Po tem, ko smo objavili aplikacijo na Play Store, smo prosili prijatelje in sodelavce, naj poskusijo aplikacijo. Med uporabo so naleteli na nekaj pričakovanih in nepričakovanih problemov.
== Ni intuitivno, kako uprabljati aplikacijo
Uporabnikom ni bilo jasno kako uporabiti aplikacijo, ni jim bilo jasno da lahko povlečejo sliko levo ali delsno da označijo ali jim je všeč ali ne. Da rešimo to lahko ob prvem zagonu aplikacije prikažemo animacijo kako lahko premikajo sliko po zaslonu.
Uporabnikom ni bilo jasno, kako uporabiti aplikacijo, ni jim bilo, jasno da lahko povlečejo sliko levo ali desno, da označijo, ali jim je všeč ali ne. Da rešimo to, lahko ob prvem zagonu aplikacije prikažemo animacijo, kako lahko premikajo sliko po zaslonu.
== Nepričakovani rezultati
Po razlagi kako uporabljati aplikacijo jim ni bilo jasno zakaj niso videli nobenih sprememb na drevesih in v rezultatu podobnosti. Tukaj je glavni problem majhno stevilo vzorcev na generacijo (trenutno 16) s tem težko izločimo kaj je uporabniku všeč. Med testiranjem pa nam večje število vzorcev ni bilo všeč ker predolgo traja da pridemo skozi generacijo, in vidimo spremembe. In med izdelavo aplikacije, ker smo vedeli kako deluje algoritem, nismo uporabljali aplikacijo kot uporabnik. Namesto da bi izbirali izgled celotne slike smo izbirali specifične lastnosti na slikah. Nekaterim uporabnikom je tudi ratalo to ugotoviti in so s tem ustvarili precej lepe slike.
Po razlagi, kako uporabljati aplikacijo, jim ni bilo jasno, zakaj niso videli nobenih sprememb na drevesih in v rezultatu podobnosti. Tukaj je glavni problem majhno število vzorcev na generacijo (trenutno 16); s tem težko izločimo, kaj je uporabniku všeč. Med testiranjem nam večje število vzorcev ni bilo všeč, ker predolgo traja, da pridemo skozi generacijo in vidimo spremembe.Ker smo vedeli kako deluje algoritem, med izdelavo aplikacije te nismo uporabljali kot uporabnik. Namesto da bi izbirali videz celotne slike, smo izbirali specifične lastnosti na slikah. Nekaterim uporabnikom je to vspelo ugotoviti in so s tem ustvarili precej lepe slike.
== Moteč rezultat podobnosti
Nekaj uporabnikov nam je sporočilo da jih je motili da jim ni uspelo doseči 100% podobnost. Da lahko to rešimo bi mogoče lahko uporabili kak drugačen algoritem, ali bi pa lahko preslikali rezultat, da vsaka vrednost nad 85% se prikaže kot 100%.
Nekaj uporabnikov nam je sporočilo da jih je motilo, da jim ni uspelo doseči 100 % podobnosti. Da lahko to rešimo, bi mogoče lahko uporabili kak drugačen algoritem ali pa bi lahko preslikali rezultat, da se vsaka vrednost nad 85 % prikaže kot 100 %.
== Zgodovina
Uporabniki so želeli zgodovino. To bi bilo dokaj enostavno dodati saj hranimo celotno stanje aplikacije v sitemu v primeru da lahko stanje preživi izklop aplikacije. Samo med izdelavo se nismo spomnili da bi dodali zgodovino.
Uporabniki so želeli zgodovino. To bi bilo dokaj enostavno dodati, saj hranimo celotno stanje aplikacije v sistemu, da lahko stanje preživi izklop aplikacije ampak se med izdelavo nismo spomnili, da bi dodali zgodovino.
#pagebreak()
@@ -1422,20 +1421,20 @@ Uporabniki so želeli zgodovino. To bi bilo dokaj enostavno dodati saj hranimo c
Izkušnje, ki smo jih pridobili med izdelavo aplikacije.
== Strežnik in podatkovna baza
Med izdelavo aplikacije smo izdelali strežnik in odjemalec sistem da smo lahko pridobili podatke o uporabnikih in njihovih preferencah. To nas je naučilo nekaj stvari.
Med izdelavo aplikacije smo izdelali _sistem strežnik in odjemalec_, da smo lahko pridobili podatke o uporabnikih in njihovih preferencah. To nas je naučilo nekaj stvari.
- Omeji število prejetih podatkov na povezavo, da se nemore nekdo samo povezati in začeti pošiljati naključne podatke.
- Omeji kdo se lahko poveže, z uporabo nekega skrivnostnega ključa ali z registracijo.
- Uporabi prepovedni sistem, če se odjemalec lepo ne obnaša mu prepovej povezavo na strežnik.
- Med filtriranjem podatkov v podatkovni bazi ikoli ne briši samo označi, da je izbrisano.
- Omeji število prejetih podatkov na povezavo, da senemore nekdo samo povezati in začeti pošiljati naključnih podatkov.
- Omeji, kdo se lahko poveže z uporabo nekega skrivnostnega ključa ali z registracijo.
- Uporabi prepovedni sistem, če se odjemalec ne obnaša lepo mu prepovej povezavo na strežnik.
- Med filtriranjem podatkov v podatkovni bazi nikoli ne briši samo označi, da je izbrisano.
- Naj odjemalec pošlje vse podatke na enkrat.
- Imej paritetne kode
Naš sistem je bil tako narejen da je vsak odjemalec imel skrivno stevilko ki jo je uporabil pri komunikaciji, samo smo še vedno naleteli da se je naključno lahko nekdo povezal na strežnik in je zadel število, in ker nismo imeli dobre filtracije podatkov se je vse kar nam je poslal direktno shranjevalo v bazo. Bi bilo dobro da imamo paritetne kode na koncu sporočila da vemo ali je sporočilo validno. Na to ko nam je zlonamerni udjemalec napolnil bazo smo se odločilo da bomo odstranili vse podatke ki ne sledijo pravilni evoluciji, in ker smo imeli napako v kodi smo si zbrisali celotno bazo podatkov. Med testiranjem smo tudi našli par primerov kjer se sporočila niso prenesla v celoti.
Naš sistem je bil tako narejen, da je imel vsak odjemalec skrivno številko, ki jo je uporabil pri komunikaciji, ampak smo še vedno naleteli na to, da se je lahko nekdo naključno povezal na strežnik in je zadel število, in ker nismo imeli dobre filtracije podatkov, se je vse, kar nam je poslal, direktno shranjevalo v bazo. Bilo bi dobro, da imamo paritetne kode na koncu sporočila, da vemo, ali je sporočilo validno. Ko nam je zlonamerni odjemalec napolnil bazo, smo se odločili, da bomo odstranili vse podatke, ki ne sledijo pravilni evoluciji, in ker smo imeli napako v kodi, smo zbrisali celotno bazo podatkov. Med testiranjem smo našli tudi par primerov, kjer se sporočila niso prenesla v celoti.
#pagebreak()
== Gradilni sistem
Začeli smo z enostavno Makefile datoteko kjer smo enostavno samo vse kompilirali skupaj.
Začeli smo z enostavno Makefile datoteko, kjer smo vse enostavno kompilirali skupaj.
```Makefile
gcc -c raylib.c -o raylib.o
@@ -1443,16 +1442,16 @@ g++ -c main.cpp -o main.o
g++ main.o raylib.o -o main
```
Ampak je to čez čas postalo, kar naporno za upravljanje, ko se je število datotek povečevalo in razvijali smo na dveh operacijskih sistemih (Linux in Windows) in po tem smo naredili našo največjo napako. Navdihnil nas je tsoding nob.h @git_nob in odločili smo se da bomo napisali svojo skripto za gradno, ki bo pravilno izbrala pravi prevajalnik g++ za Linux in zig c++ za Windows. To je delovalo prej dobbro, vendar smo sčasoma več časa porabili za skripto kot za naš projekt.
To je čez čas postalo kar naporno za upravljanje, ko se je število datotek povečevalo in razvijali smo na dveh operacijskih sistemih (Linux in Windows). Potem smo naredili največjo napako. Navdihnil nas je tsoding nob.h @git_nob in odločili smo se da, bomo napisali svojo skripto za gradnjo, ki bo pravilno izbrala pravi prevajalnik g++ za Linux in zig c++ za Windows. To je delovalo precej dobro, vendar smo sčasoma več časa porabili za skripto kot za naš projekt.
Prišlo je do točke kjer je skripta lahko
- Izvajala ukaze
- Preverjala če se je skripta spremenila in se je nato sama ponovno zgradila
- Dodali smo inkrementalno gradnjo projekta
- Prenesla in kompilirala raylib
- Na koncu smo celo dodali da lahko skompilira vse datoteke v direktoriju
Prišlo je do točke, kjer:
- je skripta lahko izvajala ukaze,
- preverjala, če se je skripta spremenila, in se je nato sama ponovno zgradila,
- smo lahko dodali inkrementalno gradnjo projekta,
- je skripta lahko prenesla in kompilirala raylib,
- smo na koncu celo lahko dodali, da lahko skompilira vse datoteke v direktoriju.
Na to smo morali dodati še gradno enega programa, kar je bilo mogoče z našo skripto, vendar nas je motilo, koliko časa smo porabili za vzdrževanje skripte. Odločili smo se da bomo probali CMake, ki je prvo gradno malo počasnejšo saj smo morali samo prenesti raylib in druge odvisnosti, vendar je bilo vse ostalo popolno in je preprosto delovalo.
Nato smo morali dodati še gradnjo enega programa, kar je bilo mogoče z našo skripto, vendar nas je motilo, koliko časa smo porabili za vzdrževanje skripte. Odločili smo se, da bomo poskusili CMake, ki je prvo gradnjo malo počasneje saj smo morali samo prenesti raylib in druge odvisnosti, vendar je bilo vse ostalo popolno in je preprosto delovalo.
@@ -1462,11 +1461,11 @@ Na to smo morali dodati še gradno enega programa, kar je bilo mogoče z našo s
V tej diplomski nalogi smo razvili aplikacijo Treender, ki uporabnikom omogoča interaktivno vodenje evolucije fraktalnih dreves z uporabo genetskih algoritmov in preprostih uporabniških gest. Cilj projekta je bil raziskati, kako lahko kombinacija algoritmov in uporabniških ocen ustvarja osebne in dinamične izkušnje.
Za razvoj smo uporabljali tehnologije, kot so C++, Raylib in SQLite3, ki so omogočile učinkovito delovanje in vizualizacijo. Ključni izziv je bila optimizacija algoritmov za generiranje in risanje dreves, ki smo ga rešili z risanjem na teksturo in omejevanjem števila risalnih klicev. Ugotovili smo, da je pomembno, da je uporabniški vmesnik intuitiven, saj so uporabniki na začetku težave razumeli osnovne funkcije, kot je ocenjevanje s povlekanjem slike.
Za razvoj smo uporabljali tehnologije, kot so C++, Raylib in SQLite3, ki so omogočile učinkovito delovanje in vizualizacijo. Ključni izziv je bila optimizacija algoritmov za generiranje in risanje dreves, ki smo ga rešili z risanjem na teksturo in omejevanjem števila risalnih klicev. Ugotovili smo, da je pomembno, da je uporabniški vmesnik intuitiven, saj so uporabniki na začetku težko razumeli osnovne funkcije, kot je ocenjevanje z vlečenjem slike.
Za izračun podobnosti med drevesi smo izbrali Hammingovo razdaljo, saj je nudila enostavno implementacijo in jasne rezultate. Objava aplikacije na Google Play Store je zahtevala prilagoditve opisa in politike zasebnosti, da smo ustrezali zahtevam platforme.
Projekt je uspešno dosegel svoje cilje: uporabnikom je omogočil ustvarjanje in prilagajanje fraktalnih dreves, hkrati pa nam je prinesel dragocene izkušnje na področju razvoja, optimizacije in uporabniškega izkušenj. V prihodnosti bi lahko aplikacijo izboljšali z dodajanjem zgodovine in izboljšavo komunikacije podobnosti.
Projekt je uspešno dosegel svoje cilje: uporabnikom je omogočil ustvarjanje in prilagajanje fraktalnih dreves, hkrati pa nam je prinesel izkušnje na področju razvoja, optimizacije in uporabniške izkušnje. V prihodnosti bi lahko aplikacijo izboljšali z dodajanjem zgodovine in komunikacije podobnosti.
#pagebreak()
#bibliography("citations.bib", title: [VIRI IN LITERATURA], style: "ieee.csl")