[C++] Kip-ei probleem met iterators

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Stukfruit
  • Registratie: Oktober 2007
  • Niet online
Ik heb een 2d array, waar ik een iterator op wil loslaten (geen stl, wel vergelijkbaar) om een serie objecten die aan een stuk door naast en onder elkaar liggen te vinden. Voor deze iterator moet ik zelf een methode implementeren om het mogelijk te maken om door de objecten in de 2d array te wandelen.

Nu ben ik al dagenlang bezig om uit te vinden hoe ik dit het beste kan aanpakken. Het lijkt makkelijk, maar blijkbaar is het toch best moeilijk! (of ik denk weer eens te moeilijk :P :$ )

Normaal gesproken zou je voor een 2d array zo er overheen kunnen gaan om bv. positie <10,10> te vinden:

C++:
1
Object* ob = 2darray->index(10,10);


Helaas kan ik dat niet doen, omdat ik:

• Niet de objecten op zich wil benaderen (het is eigenlijk een abstractie van een groter geheel, waardoor ik aan een enkel of een paar aparte object(en) in de meeste gevallen niet veel heb)

• Verschillende offsets moet berekenen, wat in dit geval eigenlijk alleen maar iteratief kan. Latere waarden uit latere objecten uit de array hebben bijna altijd variabele offsets en zijn oa. daardoor afhankelijk van eerdere objecten (het iteraten moet dan ook perse van links naar rechts en van boven naar beneden in de array gaan)

Dan kan ik altijd nog een while-loopje gebruiken, maar dat wordt erg vies en moet dan op veel plaatsen door het programma heen gesprenkeld worden (steeds weer hetzelfde). Aangezien dat een goede methode is om beestjes te kweken blijf ik daar liever ver bij vandaan.

Het komt er op neer dat ik in de methode van de iterator om vooruit te lopen, oa. het volgende moet bijhouden:

• De positie van X
• De positie van Y
• Steeds wanneer X aan het eind komt moet X gereset worden naar de beginwaarde en moet Y++;

Een van de vele pogingen die ik heb geprobeerd is hieronder te zien. Het is pseudo code en kan zijn dat het niet helemaal werkt, maar het gaat om het idee.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//
// c'tor van de iterator
//

_current_xindex = x_end + 1;
_current_yindex = y_begin - 1;


//
// "next" methode van de iterator
//

if (_current_xindex > x_end) {
  // Yup, aan het einde, ga terug naar het begin
  _current_xindex = x_begin;

  if (_current_yindex > y_end) {
    // Wanneer we alle rijen hebben gehad retourneren we false terug
    // om aan te geven dat de iteratie kan stoppen en de bewerking klaar is...
    return false;
  }
  else {
    // Op naar de volgende rij...
    _current_yindex++;
  }
}
else {
  // Om hier vervolgens weer naar rechts toe te zwemmen...
  _current_xindex++;
}

// Er zijn nog enkel wachtenden, kom svp later nog eens terug
return true;


//
// Uiteindelijk gebruik:
//

Iterator it( Rectangle(10,10,100,100) );
while (it.next()) {
  // Doe iets leuks met de data...
}


In mijn echte code heb ik een aantal variabelen die afhankelijk zijn van x en y, zoals hierboven aangegeven door _current_xindex en _current_yindex. Deze variabelen mogen alleen opnieuw berekend worden wanneer het ook relevant is, dus alleen als de iterator bezig is met het langsgaan van de kolommen (x) van de array, en de anderen alleen wanneer de iterator bezig is met het langsgaan van de rijen (y).

Het grote probleem is dat die variabelen afhankelijk zijn van de huidige indexwaardes, niet vooraf berekend kunnen worden, maar wel na 1 enkele aanroep van "next" de juiste waarden moeten bevatten. Dit hebben ze echter niet, er blijft bij een eerste iteratie altijd een waarde met troep gevuld (of een waarde die in de c'tor is toegewezen) omdat ik in die "next"-methode maar 1 ding tegelijk kan doen en ze niet allebei tegelijk eerst berekend kunnen worden: x, of y. Oftewel; eerst de kip, of het ei.

Ik hoop dat de vraag zo een beetje duidelijk gesteld is: wie weet hoe ik het iteratief door een tweedimensionale array heenlopen wat eleganter kan aanpakken, en vooral ook altijd goed werkend? :)


ps. Voor wie het nog niet door had, ik ben dus een tekenprogramma aan het maken ;)

Dat zit wel Schnorr.


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik zou eens kjiken naar GIL ( http://opensource.adobe.c...gil/Generic+Image+Library ) en naar VIGRA ( http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ ) dat zijn allebei C++ image libraries. De eerste is open source van Adobe, een onderdeel van Boost en gebasseerd op generics/templates. De tweede is een object georienteerde aanpak die enigszins gebasseerd is op de STL (image iterators etc.)

(VIGRA image iterators: http://kogs-www.informati...roup__ImageIterators.html )

(en deze natuurlijk: STL-Style Generic Programming with Images, in: C++ Report Magazine 12(1), January 2000)

[ Voor 28% gewijzigd door Zoijar op 02-12-2008 10:05 ]


Acties:
  • 0 Henk 'm!

  • Stukfruit
  • Registratie: Oktober 2007
  • Niet online
Bedankt voor je reactie en de links :)

Hoewel de hint duidelijk was (ik moet geen 1d iterator gebruiken voor 2d spul, domdom :$ ) zijn GIL en Vigra (wat een naam zeg) voor dingen bedoeld die een laag lager liggen.

Wat ik hierboven beschreef was eigenlijk een tile-systeem, waaruit ik tiles wilde opvragen, en daarin zit pas de pixeldata zelf:
Afbeeldingslocatie: http://i37.tinypic.com/2nqqm3s.jpg

In bovenstaande afbeelding geven de blauwe lijnen tile boundaries aan en de rode lijnen de omtrek van een afbeelding (bijvoorbeeld het masker van een brush) die naar de (getilede) afbeelding gecopieerd moet worden. Het is echt een verschrikkelijk rotsysteem om goed in elkaar te zetten, maar er is geen enkele andere manier om tot m'n doel te komen... :/

Ik zou bv. wel GIL kunnen gebruiken (bedankt voor de link, in de toekomst ga ik daar absoluut gebruik van maken _/-\o_ ), alleen GIL noch Vigra ondersteunen voor zover ik kan zien het gebruik van afbeeldingen bestaande uit tiles. Wel sub views, maar daar heb ik niet veel aan omdat er oa. tiles kunnen ontbreken (bv. omdat ze zijn weggeschreven naar tijdelijk geheugen). Een "virtueel" view via GIL is ook geen oplossing omdat het dan veel te langzaam zou worden ivm checks die voor iedere pixel nodig zijn om te zien of de pixel niet van een tile afloopt of dat er uberhaupt wel een tile bestaat op die locatie.

Wat me ondertussen wel heel duidelijk is, is dat ik er echt helemaal verkeerd over heb nagedacht. Op het moment kan ik op een iets andere manier alle aparte stukjes van een deel van de getilede afbeelding opvragen (zie rode rechthoek hierboven) en die stuk voor stuk bewerken. Een gebruiker van de code heeft nu niet meer rechtstreeks met de tiles te maken, dus op zich is dat al een flinke verbetering.

Het is alleen erg jammer dat ik daardoor nu wel eerst alles naar een tijdelijke buffer moet copieeren (en na de bewerking weer terug!) om er bv. convoluties op los te laten, omdat daar minstens 1 pixel rondom iedere normale pixel nodig is en die extra pixel er niet altijd is met al die losse "patches".

Mocht iemand daar nog iets op weten, dan zou ik die persoon eeuwig dankbaar zijn :)

Dat zit wel Schnorr.