[Delphi] Case sneller maken

Pagina: 1
Acties:

  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
Ik hier een stukje code waarmee ik op een laag alle features af ga en kijk van welk type het is. Aan de hand van het type maak ik een Button visible. Het probleem is alleen dat de functie FLayer.AllFeatures.Item(i).Type_ heel erg traag is. Zeg maar -> met een Count van 6000 doe ik er ongeveer 7 minuten over :( .

Hoe kan ik dit sneller maken zonder de FLayer.AllFeatures.Item(i).Type_ functie (omdat het niet kan) aan te passen?

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  sbtnPickRegion.Visible := false;
  sbtnPickLine.Visible := false;
  sbtnPickSymbol.Visible := false;
  sbtnPickText.Visible := false;

  for i := 1 to FLayer.AllFeatures.Count do
  begin
    //Dit helpt niet echt omdat het zelden voorkomt dat ze allemaal op 1 laag zitten
    //if sbtnPickRegion.Visible and sbtnPickLine.Visible and
    //   sbtnPickSymbol.Visible and sbtnPickText.Visible
    //then
    //  Break;
    case FLayer.AllFeatures.Item(i).Type_ of
      miFeatureTypeRegion: sbtnPickRegion.Visible := true;
      miFeatureTypeLine: sbtnPickLine.Visible := true;
      miFeatureTypeSymbol: sbtnPickSymbol.Visible := true;
      miFeatureTypeText: sbtnPickText.Visible := true;
    end;
  end;

Aye aye captain


  • Varienaja
  • Registratie: Februari 2001
  • Laatst online: 14-06 16:43

Varienaja

Wie dit leest is gek.

Je kunt een 'cache' maken. Gewoon een TList, waarin je 1x van ieder item het Type_ opslaat.

Vervolgens gebruik je daarna steeds de (snelle) cache om te bepalen welk Type_ feature[i] heeft.

[ Voor 12% gewijzigd door Varienaja op 28-03-2003 12:25 ]

Siditamentis astuentis pactum.


  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
Maar het probleem is dan straks dat je 7 minuten moet wachten voordat alles is opgeslagen in de TList.

Aye aye captain


  • Varienaja
  • Registratie: Februari 2001
  • Laatst online: 14-06 16:43

Varienaja

Wie dit leest is gek.

Weng schreef op 28 maart 2003 @ 12:31:
Maar het probleem is dan straks dat je 7 minuten moet wachten voordat alles is opgeslagen in de TList.
Maar vervolgens kan je iedere volgende keer in een paar tellen klaar zijn.

Siditamentis astuentis pactum.


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10 16:44
Als je zeker weet dat Type_ de bottleneck is dan is er weinig aan te doen denk ik. Als je nl bijv. 6000 elementen hebt dan zal je toch echt 6000 keer Type_ moeten doen. Weet je zeker dat _Type de bottlenck is en niet bijv. item()? Als je dat niet zeker weet kan je het natuurlijk makkelijk testen door bijv. Item(1) op te slaan en dan bijv. 6000 keer Type_ aanroepen op dat element.

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Weng schreef op 28 March 2003 @ 12:31:
Maar het probleem is dan straks dat je 7 minuten moet wachten voordat alles is opgeslagen in de TList.

Volgens mij niet ;) Je zit volgens mij hier met een LinkedList (oid) datastructuur te werken en bent daarmee bezig met random access. De oplossing zou imho dan ook zijn (mocht mijn aanname correct zijn) om een ArrayList te nemen, welke O(n) qua RA heeft.

Als je vervolgens een LinkedList gaat converteren naar een ArrayList ga je dat doen dmv een Iterator. De iterator zal de List zo effectief mogelijk aflopen (en dus onthouden waar ie was, en niet telkens op 0 beginnen) zodat het geen 7 minuten zal duren.

Let er wel op dat dit allemaal gebaseerd is op een gok op het Type van FLayer.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Jouw code voert 6000x een Paint opdracht uit. Gebruik tijdelijke variablen en ken die pas na de hand toe aan Visible.

/edit
PS: Weet je zeker dat dat array van 1 naar Count loopt? Dat is niet heel gebruikelijk.

[ Voor 30% gewijzigd door LordLarry op 28-03-2003 13:54 ]

We adore chaos because we like to restore order - M.C. Escher


  • nightwatcher_b
  • Registratie: Mei 2002
  • Laatst online: 08-12 19:51

nightwatcher_b

When the wolves are crying

Misschien heb je hier wat aan?

Delphi:
1
2
3
4
5
6
7
8
9
10
11
Zichtbaar(Flayer);

Procedure Zichtbaar(Sender:TWinControl);
var t:integer;
begin
  with Sender do
  begin
    for t:=0 to ControlCount-1 do
      Controls[t].Visible:=true;
  end;
end;{Zichtbaar}

Alle componenten op Flayer worden nu zichtbaar (als het goed is :) ).

/edit
Damm lastig dat spaties weg worden gehaald
/edit

edit:
Zo beter ;) --Glimi

[ Voor 17% gewijzigd door Glimi op 28-03-2003 14:11 . Reden: Spaties weg?? ]


  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
LordLarry schreef op 28 March 2003 @ 13:52:
Jouw code voert 6000x een Paint opdracht uit. Gebruik tijdelijke variablen en ken die pas na de hand toe aan Visible.

/edit
PS: Weet je zeker dat dat array van 1 naar Count loopt? Dat is niet heel gebruikelijk.
Ja, weet zeker dat hij van 1 naar count loopt. Ik vond het ook al heel raar waarom ze het zo hebben gedaan.

Ik heb al geprobeerd om er if button.Visible <> true omheen te zetten, maar dat maakt geen verschil.

Aye aye captain


  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
TijnFLiP schreef op 28 maart 2003 @ 13:45:
Als je zeker weet dat Type_ de bottleneck is dan is er weinig aan te doen denk ik. Als je nl bijv. 6000 elementen hebt dan zal je toch echt 6000 keer Type_ moeten doen. Weet je zeker dat _Type de bottlenck is en niet bijv. item()? Als je dat niet zeker weet kan je het natuurlijk makkelijk testen door bijv. Item(1) op te slaan en dan bijv. 6000 keer Type_ aanroepen op dat element.
Het probleem ligt inderdaad in de Item(i).

Aye aye captain


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10 16:44
Wat is die AllFeatures precies voor n class ? Item() is misschien zeer ineffectief geimplementeerd. Maar misschien gebruikt AllFeatures wel onderhuids een Enumerator (is het een COM object?) en start ie telkens weer bij 1 en stapt ie verder tot i. Misschien kan je een enumerator gebruiken (IEnumVARIANT?) ?

  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
Ik zal even wat meer info geven:

Ik maak gebruik van een bestaande Gis-ActiveX (Geografisch Info Systeem) component van MapInfo (MapX). Ik heb dus geen idee hoe de onderliggende code in elkaar zit.

Aye aye captain


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10 16:44
Loop de tijd lineair op bij het verhogen van het aantal te doorlopen features? dus, duurt het 10 X zo lang om van 1 tot 1000 te doorlopen als dat het duurt om van 1 to 100 te doorlopen? als dat NIET zo is dan valt er zowiezo denk ik niet veel aan te doen want is Item() op zich 'goed' geimplementeerd. Als de tijd nou exponentieel op loopt dan zou je (als dat uberhaupt mogelijk is) nog kunnen winnen door te kijken of er een enumerator gebruikt kan worden.

[Edit] Wat je ook nog kan proberen is het cachen van FLayer.AllFeatures. Dus voor de for loop sla je FLayer.AllFeatures op in een tijdelijke var. Het zou kunnnen dat ie anders steeds FLayer.AllFeatures moet opbouwen (AllFeatures lijkt ook een collection te zijn die misschien niet intern gecached is)

[ Voor 26% gewijzigd door martijn_brinkers op 28-03-2003 15:27 ]


  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
De tijd loopt exponentieel op:
Count 200: +/- 4 sec
Count 6000: +/- 7 min

Wat is een Enumerator?

Ik zal AllFeatures eens in een tijdelijke var zetten, maar ik vrees dat het niets zal uithalen.

Aye aye captain


  • Elissen
  • Registratie: Januari 2000
  • Laatst online: 24-02 12:16
Met een enumerator/iterator kan je sequentieel door de lijst heen, zoals Glimi zei, met bijvoorbeeld een .next-procedure.
Het probleem nu is waarschijnlijk dat als je item 1000 wilt hebben dat die de start pakt en dan 999 keer verder gaat om bij het duizendste item te komen. Als je item 1001 wilt hebben begint die eerst weer bij een. (Als dit echt zo is moet een for van 1 t/m 1000 sneller gaan dan 5000 t/m 6000).

Kijk even zoals ook door anderen aangegeven naar een enumerator of iterator.

  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
Dus als ik het goed begrijp is een enumerator hetzelfde als een Iterator?

Ik heb al gekeken naar een iterator, maar dat heeft ie dus niet :( Ik denk dan ook niet dat er een andere manier is om dit op te lossen :'( Iig bedankt voor jullie replies.

Aye aye captain


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10 16:44
Ik zal AllFeatures eens in een tijdelijke var zetten, maar ik vrees dat het niets zal uithalen
Heb je dat al geprobeerd?

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 16-12 11:47

Tomatoman

Fulltime prutser

Kun je met een profiling tool niet achterhalen welke regel/regels de boosdoener is/zijn?

Een goede grap mag vrienden kosten.


Verwijderd

Zo uit m'n hoofd zeg ik dat je even moet kijken of je kunt voorkomen dat je app. gaat repainten na elke iteratie. Hoe je dit zou moeten doen kan ik je zo niet zeggen, maar volgens mij kan het wel.

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 16-12 11:47

Tomatoman

Fulltime prutser

Eerst maar eens alle paint acties verwijderen:
Delphi:
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
type
  TVisibleBtn = (vbPickRegion, vbPickLine, vbPickSymbol, vbPickText);
  TVisibleBtns = set of TVisibleBtn;
const
  AllVisible = [vbPickRegion, vbPickLine, vbPickSymbol, vbPickText];
var
  Visibility = TVisibleBtns;
begin
  Visibility := [];
  for i := 1 to FLayer.AllFeatures.Count do
  begin
    case FLayer.AllFeatures.Item(i).Type_ of
      miFeatureTypeRegion: Include(Visibility, vbPickRegion);
      miFeatureTypeLine: Include(Visibility, vbPickLine);
      miFeatureTypeSymbol: Include(Visibility, vbPickSymbol);
      miFeatureTypeText: Include(Visibility, vbPickText);
    end;
    if Visibility = AllVisible then
      Break;
  end;
  sbtnPickRegion.Visible := vbPickRegion in Visibility;
  sbtnPickLine.Visible := vbPickLine in Visibility;
  sbtnPickSymbol.Visible := vbPickSymbol in Visibility;
  sbtnPickText.Visible := vbPickText in Visibility;
end;

Wat ook heel veel kan schelen, is het inbouwen van wat aannamen over hoe de layers zijn opgebouwd. Misschien is het wel sneller om van Count terug te tellen naar 1, om maar een voorbeeld te noemen.

Nu een optimalisatie die ergens moet staan voordat FLayer.AllFeatures wordt gevuld met items, bijvoorbeeld direct na FLayer.AllFeatures.Create of in de constructor van AllFeatures:
Delphi:
1
  FLayer.AllFeatures.Capacity := 4096;  // of een andere waarde
Dat verhelpt jouw probleem niet, maar het scheelt wel een hoop snelheid als de list gevuld wordt.

Verder moet je heel erg oppassen met TList.IndexOf(), want die method is traaaaag.

Een goede grap mag vrienden kosten.


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 15-12 18:15

alienfruit

the alien you never expected

Tomatoman, je kunt natuurlijk ook BeginUpdate() en EndUpdate() dan lockt ie ook de paint methode :)

Verwijderd

Dat is 'm idd, die bedoelde ik.. ik denk dat daar z'n probleem gelijk mee opgelost is (die beginupdate en endupdate)

//edit
off-topic: bah, die breaks.. leer dat nou eens af mensen, break+exit = no go

[ Voor 31% gewijzigd door Verwijderd op 29-03-2003 13:43 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 16-12 11:47

Tomatoman

Fulltime prutser

Verwijderd schreef op 29 maart 2003 @ 13:42:
off-topic: bah, die breaks.. leer dat nou eens af mensen, break+exit = no go
  • Vertel mij eens wat er mis is met de Break in het voorbeeld.
  • Herschrijf de code zodanig dat de Break er niet meer is EN dat de code er duidelijker op wordt.
Edit:
Delphi:
10
11
12
13
14
15
16
17
 for i := 1 to FLayer.AllFeatures.Count do
  if Visibility <> AllVisible then
    case FLayer.AllFeatures.Item(i).Type_ of
      miFeatureTypeRegion: Include(Visibility, vbPickRegion);
      miFeatureTypeLine: Include(Visibility, vbPickLine);
      miFeatureTypeSymbol: Include(Visibility, vbPickSymbol);
      miFeatureTypeText: Include(Visibility, vbPickText);
    end;
Dit is natuurlijk waar jij op doelt, maar dan doorloop je een paar duizend keer onnodig een lus (for) en check je evenzovele keren (if) een statement waarvan je de uitkomst allang weet. Je maakt je code dus bewust inefficiënt, simpelweg omdat je een Break wilt voorkomen. Ik zie daarin echt geen voordelen.

[ Voor 51% gewijzigd door Tomatoman op 29-03-2003 14:20 ]

Een goede grap mag vrienden kosten.


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10 16:44
Zoals Weng al heeft aangegeven gebruikt hij een MapX activeX object. AllFeatures is dus geen TList en heeft zodoende ook geen Capacity property (althans volgens http://testdrive.mapinfo.com/mapxhelp/map00336.htm ). Ik denk dat de enige mogelijke optimalisatie (afgezien een mogelijke winst door het onderdrukken van de paintings) misschien het cachen van AllFeatures is. Dit omdat misschien het Layer object steeds een nieuwe Features object aanmaakt bij de call naar AllFeatures ( zie http://testdrive.mapinfo.com/mapxhelp/map00414.htm ).

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 16-12 11:47

Tomatoman

Fulltime prutser

TijnFLiP schreef op 29 March 2003 @ 14:17:
Zoals Weng al heeft aangegeven gebruikt hij een MapX activeX object. AllFeatures is dus geen TList en heeft zodoende ook geen Capacity property (althans volgens http://testdrive.mapinfo.com/mapxhelp/map00336.htm ).
Oeps, over het hoofd gezien :o. Ik ken MapX absoluut niet, maar volgens de help files kun je Layer.BeginAccess() en Layer.EndAccess() gebruiken om lees- en/of schrijftoegang te versnellen. Verder kom ik Features.Clone() en Features.Common() tegen:
http://www.mapinfo.com/free/docs/mapx/MapX_50_DevGuide.pdf, pagina 104:
Clone - Make a copy of the collection as another Features collection
object.
Common - Combine this collection and another Features collection so that this collection contains only features that are in both (INTERSECT set operation).
Volgens mij kun je daarmee precies doen wat jij wilt. Eerst maak je een kloon van FLayer.Features. Vervolgens maak je een Features object met daarin alleen de feature waarvan je wilt weten of die aanwezig is. Dan doe je
[kloon van FLayer.Features].Common([Features object met te controleren feature])
Als dit een lege verzameling oplevert, is de bewuste feature niet aanwezig. Tenslotte moet je de kloon en het Features object met de te controleren feature opruimen.

Dit proces herhaal je voor allevier de features die je op hun aanwezigheid wilt checken.

[ Voor 4% gewijzigd door Tomatoman op 29-03-2003 15:14 ]

Een goede grap mag vrienden kosten.


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 15-12 18:15

alienfruit

the alien you never expected

Wat kun je eigenlijk doen met die ActiveX control? Routes plannen?
Zoja, waarom gebruik je niet een van die webservices die je ook plaatjes teruggeeft met route er op :-)

[ Voor 45% gewijzigd door alienfruit op 29-03-2003 17:03 ]


  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
alienfruit schreef op 29 March 2003 @ 17:01:
Wat kun je eigenlijk doen met die ActiveX control? Routes plannen?
Zoja, waarom gebruik je niet een van die webservices die je ook plaatjes teruggeeft met route er op :-)
Nouhou... Je kan hiermee je eigen GIS-Applicatie bouwen. Wat je daarmee kan is kaarten maken waaraan je informatie kan koppelen van bv uit een DB. Je hebt bv een kaart van Nederland. Je kan dan gaan inzoomen en dat het dan steeds gedetailleerder wordt. Je kan dan per object info opvragen bv van een perceel of het verontreinigd is en nog veel meer......

Maar dat moet je zelf maar lezen :)

Aye aye captain


  • Weng
  • Registratie: Juni 2001
  • Laatst online: 11-05-2024

Weng

Are y'all ready kids

Topicstarter
tomatoman schreef op 29 maart 2003 @ 15:11:
[...]
Oeps, over het hoofd gezien :o. Ik ken MapX absoluut niet, maar volgens de help files kun je Layer.BeginAccess() en Layer.EndAccess() gebruiken om lees- en/of schrijftoegang te versnellen. Verder kom ik Features.Clone() en Features.Common() tegen:
[...]
Volgens mij kun je daarmee precies doen wat jij wilt. Eerst maak je een kloon van FLayer.Features. Vervolgens maak je een Features object met daarin alleen de feature waarvan je wilt weten of die aanwezig is. Dan doe je
[kloon van FLayer.Features].Common([Features object met te controleren feature])
Als dit een lege verzameling oplevert, is de bewuste feature niet aanwezig. Tenslotte moet je de kloon en het Features object met de te controleren feature opruimen.

Dit proces herhaal je voor allevier de features die je op hun aanwezigheid wilt checken.
Ik zal hier naar kijken, bedankt voor de tip!

[ Voor 12% gewijzigd door Weng op 29-03-2003 19:48 ]

Aye aye captain

Pagina: 1