Laden...

Eine (Land)Karte aus Koordinaten erzeugen

Erstellt von SirSydom vor 17 Jahren Letzter Beitrag vor 17 Jahren 7.088 Views
SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren
Eine (Land)Karte aus Koordinaten erzeugen

Hi!

Ich bin dabei eine Anwendung zu schreiben die ein Koordiantensstem als Karte darstellen soll. Man soll auf dieser Karte dann zoomen können und den Mittelpunkt verschieben.

Ich habe eine (virtuelle) Landschaft, bestehend aus einem Koordinatensystem (1000 x 1000).

In diesem Koordinatensystem möchte ich Punkte einzeichnen, die mir bekannt sind.

Das sind im Moment knapp 70.000 Punkte, können aber auch bis zu 500.000 Punkte werden.

Diese Punkte werden durch x und y Koordinaten spezifiziert und haben noch etwas Nutzdaten.

Ich möchte nun das diese Punkte eingezeichnet werden (je nach Nutzdaten auch in andere Farbe usw) und man beim Mouseover über einen bestimmten Punkt bzw Klick soll noch Infos irgendwo angezeigt werden.

Wie realisiere ich sowas am besten?

Ich habs mal ausprobiert einfach sntsprechende Rectangles mit Draw in der OnPaint Methode, aber das ist sowas von langsam das geht auf keinen Fall.

Hat jemand einen Denkanstoss wie ich das eleganter und vor allem performanter lösen könnte?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo SirSydom,

zeichne nur die Punkte, die momentan auch zu sehen sind. Zeiche diese in das Image einer PictureBox. So hast du den Aufwand pro Zoomstufe nur einmal, danach wird einfach das Image angezeigt (PictureBox.Invalidate).

herbivore

I
1.739 Beiträge seit 2005
vor 17 Jahren

Irgendwie hab ich das Gefühl das dur nicht klar bist über die Frage.
Kannst du dein Problem näher spezifizieren?
Koordinatensytem bleibt?(1000 x 1000)?
Auflösung kann sich andern bei derzeit 70.000 Punkte?(später 500000)
Punkt ist was, gegenüber Auflösung?
Präzisiere bitte etwas, mir jedenfalls ist lt. der Beschreibung das Problem nicht erkennbar.
Könnte ne Kartendarstellung sein(Vermutung(lol), aber wo liegt das Darstellungsproblem?).

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Das heißt ich zeichne nicht jeden Punkt auf der Karte sondern nur ganz bestimmte.

Ich könnte max. 1000000 Punkte einzeichnen dann wäre die Fläche voll gefüllt, das tue ich aber nicht, sondern zwischen den einzelnen Punkten ist eben oft Zwischenraum.

I
1.739 Beiträge seit 2005
vor 17 Jahren

Geht es um Höhendaten oder Routen?
Pixel/Flächen oder Vektoren?

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Ich hab eine Liste von Daten. Jeweils X,Y und noch ein paar Nutzdaten.

Es geht um eine (rein virtuelle) Welt mit der Größe 1000*1000 Felder.

Nun will ich diese Karte darstellen, in hohen Auflösungen mit gifs die ich schon habe, in niedrigen einfach als farbige Punkte.
Abhängig von den Nutzdaten werden verschiedene gifs eingeblendet bzw eine verschiedene Farbe benutzt.

I
1.739 Beiträge seit 2005
vor 17 Jahren

Also werde mit Hilfe der "Zwischenräume" die Gifs skaliert?
Also eine Texturmatrix?

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Ja.

Ich bin noch nicht ganz sicher ob es Zwischenräume geben wird bei denen dann sozusagen der Hintergrund durscheint oder ob jedes Feld als gif dargestellt wird.

Wird wohl beides werden abhängig von der Zoomstufe.

Kann ich in einer PictureBox mehrere Bilder darstellen?
Wenn ja, wie?
Oder brauche ich für jedes Gif eine eigene?

Und wie zeichne ich in einer Picture Box? Ich kenn zeichnen nur in der OnPaint Methode.

I
1.739 Beiträge seit 2005
vor 17 Jahren

Weisst du, das mit dem "ich bin mir nicht klar" ist ein Hauptproblem in der Entwicklung von Weichware. (Das ist so, nicht um dich zu ärgern. Mach mal nen Tisch oder Stuhl um später festzustellen, dass die Auftraggeber nicht zufrieden sind(Zwerge, Riesen oder haben die Knie hinten), Details wurden verschwiegen(mach was aws mir gefällt = "häh" -> ok ich ich versucht).

Den Schwund hab ich nur geschrieben um klarzumachen, warum es so lange dauerte bis das Problem wenigstens erkennbar ist.

>Wird wohl beides werden abhängig von der Zoomstufe.

inwiefern?

>Kann ich in einer PictureBox mehrere Bilder darstellen?

Millionen wenn du willst(es geht auch ein Label oder sonstiges).
Solls Interaktiv sein?

Oder brauche ich für jedes Gif eine eigene?
Nach beschriebenen Problem nicht unbedingt(könnte aber zur Vereinfachung praktisch sein - wenn interaktiv(Auswahl per Klick)).

>Wenn ja, wie?
Vereinfacht gesagt: Copy & Paste.(per onPaint wär Verschwendung von Rechenzeit - falsches Event()insbesondere bei PictureBox).

Wenn du dir sicher wärst. (Analysiere das Problem unabhängig von dir bekannten Lösungen und reduziere auf Notwendigkeit).
Fragen:
Gifs - immer?
Wenn nein: wo nicht/warum?

Nochmal(Höhendaten?darum lücken?)
(Diese Schwarzen Flecken wären auch Gifs(eher schwarz)?, könnte man interpolieren).

Programmiertechnisch seh ich nach diesen Infos erstmal keine zu hohen Hürden.
Hätte aber gern die Fragen beantwortet, so gut es halt geht bevor ich mich engagiere.

Nur zu Eingrenzung des Problems...

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Erstmal vielen Dank für deine Hilfe, ich weiß das sehr zu schätzen.

Ich fange am besten mal bei Adam und Eva an, damit ganz klar wird was ich will.

Es gibt da ein Browser Game bei dem ich mitspiele. In diesem Spiel existiert eine Welt die die Im Endeffekt ein Koordinatensystem ist. Jeder (diskrete, nur Ganzahlen) Punkt stellt ein Objekt dar, das einem Spieler gehören kann oder einfach nur Hintergrund darstellt.

Im Spiel exitsiert dazu eine grafische Karte, die jedoch von der Funktionalität stark eingeschränkt ist. Zusätzlich gibt es eine Schnittstelle für externe Tools, die so aussieht:


ID,Name,X,Y,Data1,Data2,Data3
1,Objectname1,494,497,3,38,64559
2,Objectname2,494,504,0,46,63468
3,Objectname3,498,487,2,215,38132
4,Objectname4,493,499,147431,3161,5008
5,Objectname5,492,502,75675,3781,2558
6,Objectname6,501,505,139487,3677,2950
7,Objectname7,495,510,199526,211,38365
8,Objectname8,509,501,0,48,63028
9,Objectname9,509,495,65233,3375,412

Damit möchte ich nun eine Karte erstellen die folgende Eigenschaften aufweißt (Requierements):

unbeschränkte Größe (was der Desktop hergibt)
horizontaler und vertikaler Scroll möglich
verschiedene Zoomstufen
Bei Click oder Mouseover auf dargestellt Objekte Anzeige der Nutzdaten
Markier-Funktion: Objekte mit bestimmten Eigenschaften anders darstellen (zB Farbe)

Gedanken zur Implementierung:

Die Maximalstufe beim Zoom soll ähnlich oder gleich aussehen wie die linke Karte.
Wobei ich hier noch nicht weiß ob ich an die Verteilung des Wasser, Waldes und der Hügel herankomme. Evtl muss ich den Hintergund überall gleich darstellen.

Alle kleineren Zoomstufen sind nicht mehr mit Bildern sondern mit verschiedenfarbigen Rechtecken, ähnlich der rechts eingeblendeten Karte.
Die kleinste Zoomstufe soll 1 Pixel pro Feld sein.

Das scrollen soll nur feldweiße stattfinden.

Ich hoffe damit sind alle deine Fragen beantwortet.

Eine Frage hätte ich noch:
Wie erzeuge ich dynamisch zur Laufzeit Objekte (zB pictureBox) in meinem Form?
Das:


        private void testToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            System.Windows.Forms.PictureBox pictureBox1;
            pictureBox1 = new System.Windows.Forms.PictureBox();
            pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
            pictureBox1.Location = new System.Drawing.Point(12, 27);
            pictureBox1.Name = "pictureBox1";
            pictureBox1.Size = new System.Drawing.Size(53, 38);
            pictureBox1.TabIndex = 2;
            pictureBox1.TabStop = false;
            ((System.ComponentModel.ISupportInitialize)(pictureBox1)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(pictureBox1)).EndInit();
            PerformLayout();
        }

haut leider nicht hin (kein Fehler, keine Reaktion).
Was mch ich falsch? (Oder bin ich gänzlich auf dem Holzweg?)

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo herbivore,

Kann ich in einer PictureBox mehrere Bilder darstellen?

Nein! Jedenfalls nicht gleichzeitig. Pro PictureBox kann man nur genau ein Bild angeben: PictureBox.Image. Du könntest aber in dieses Bild der PictureBox mehrere kleine Bilder malen.

Wenn ja, wie?

Graphics.DrawImage

Oder brauche ich für jedes Gif eine eigene?

Das solltest du auf keinen Fall machen! Siehe Optimierungsideen ?

Und wie zeichne ich in einer Picture Box? Ich kenn zeichnen nur in der OnPaint Methode.

OnPaint kannst du bei der PictureBox vergessen. Zeichne wann immer du willst in und mit Graphics.FromImage (PictureBox.Image) und rufe anschließend PictureBox.Invalidate auf.

herbivore

PS:

Wie erzeuge ich dynamisch zur Laufzeit Objekte (zB pictureBox) in meinem Form?

So wie du es gemacht hast, aber am Ende noch ein Controls.Add (PictureBox)

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

So ich bin nun schon vieeel weiter gekommen 🙂

Ich zeichne nun einfach pngs in die pictureBox und das haut wunderbar hin.

Nur eines macht mich stutzig:

Die Bilder die ich zeichne sind pngs. Die hab ich zu den Ressourcen hinzugefügt und greife per

global::WindowsApplication1.Properties.Resources.picname

darauf zu.

Nun sind diese Bilder 53*38 Pixel groß.

In meiner PictureBox werden Sie jedoch mit 70 * 50 Pixeln dargestellt.. Warum?
Ich zeichne per DrawImage.

Noch eine Frage:

Die ganzen Height und Width Werte und x und y beim zeichnen stellen immer Pixel dar, oder? also nicht cm, inch/70 oder sonstwas?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo SirSydom,

vieleicht sind die DPI-Werte der Bilder unterschiedlich?

herbivore

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Es hing wohl irgendwie mit der Auflösung zusammen.
Ich geb jetzt einfach mit an wie groß das Bild gezeichnet werden soll, dann passts.

Was ich im Moment nicht schaffe ist nachdem ich wie wild in meiner pictureBox rumgezeichnet hab mit dem Graphics Objekt, wie kann ich den Inhalt der pictureBox in ein Image Object konvertieren / laden ?

pictureBox.Image ist es ja nicht, ich zeichne ja da rein..

1.271 Beiträge seit 2005
vor 17 Jahren

Doch, es ist PictureBox.Image. Du zeichnest ja per Graphics-Objekt, das du über Graphics.FromImage(PictureBox.Image) erhältst. Somit zeichnest du auf das Bild.

A wise man can learn more from a foolish question than a fool can learn from a wise answer!
Bruce Lee

Populanten von Domizilen mit fragiler, transparenter Außenstruktur sollten sich von der Translation von gegen Deformierung resistenter Materie distanzieren!
Wer im Glashaus sitzt, sollte nicht mit Steinen werfen.

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

nein, ich zeichne so:


private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
       e.Graphics.DrawImage(...);
       e.Graphics.FillRectangle(...);
       ...
}

FromImage hat irgendwie nicht funktioniert, irgendwas mit der grafik oder so..

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Ich probiere gard mal wieder mit Graphics.FromImage() rum.

Das funktioniert aber nur, wenn die picture Box bereits einen Wert für Image hat.

Aber wo soll ich das Bild herbekommen, bevor ich es zeichne???
Dazu kommt, das meine pictureBox eine variable Größe hat.. Das heißt dass ich auch bei jeder Änderung der Größe ein neues Bild hbrauche für die entsprechende Größe..

Wie mache ich das?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo SirSydom,

Ich probiere gard mal wieder mit Graphics.FromImage() rum.

richtig! Alles andere ginge am Sinn der PictureBox vorbei.

Aber wo soll ich das Bild herbekommen, bevor ich es zeichne???

new Bitmap ()

Wie mache ich das?

entweder machst du das Bild von vorne herein groß genug, oder du erzeugst bei Größenänderungen immer eine neue Bitmap.

herbivore

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

👍

Danke.
Wie soll man da draufkommen?

Noch ne andere Frage:

in den meisten Fällen wenn das Bild neu gezeichnt wird wird es nur verschoben, also um links fällt was weg, rechts kommt was dazu oder oben unten usw usw.

Kann man da vielleicht was optimieren, weil bei 1.000.000 Rechtecken die gezeichnet werden müssen wird das etwas langsam..

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo SirSydom,

Wie soll man da draufkommen?

🙂

Kann man da vielleicht was optimieren, weil bei 1.000.000 Rechtecken die gezeichnet werden müssen wird das etwas langsam..

Du kannst sicher über Graphics.DrawImage Teile des Bildes sehr effizient an andere Stellen "verschieben".

herbivore

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

das dachte ich mir auch schon und habs auch schon versucht.

Ich scheitere aber daran, das Image zu klonen.
Ich wollte es so machen:


                Image buff = (Image)pictureBox1.Image.Clone();
                Graphics gfx = Graphics.FromImage(pictureBox1.Image);
                gfx.Clear(pictureBox1.BackColor);
                gfx.DrawImage(buff, x, y); // x und y sind zu bestimmen
                ... Sachen die noch neu gezeichnet werden müssen ...
                pictureBox1.Invalidate();

Geht aber net.. Ich krieg das klonen ned hin. (object nicht in Image konvertierbar).

Wie geht das?
Oder hast du ne Idee ohne Klonen?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo SirSydom,

hm, mit dem Cast auf Image sollte die Meldung eigentlich nicht kommen.

Aber ich denke, es geht auch ohne zu klonen. Es sollte gehen Teile des Bildes an andere Stellen desselben Bildes zu zeichnen. Falls man doch ein zweite Bild braucht, kann man dieses einfach mit new erzeugen.

herbovore

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

mit

Bitmap buff = (Bitmap)pictureBox1.Image.Clone();

gehts 🙂

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

Graphics gfx = Graphics.FromImage(pictureBox1.Image);
gfx.DrawImage(pictureBox1.Image, x, y);
pictureBox1.Invalidate();  

DAS geht nicht. Warum kann ich dir nicht sagen, aber dann hat er gar nix mehr gezeichnet, warum auch immer.

Ich hab jetzt hinbekommen und auch mit einer wahnsinnigen If-Abfrage es geschafft zu berechnen was ich nun neu zeichnen muss und was nicht - Jedoch bringt es wenig Performance-Plus.

Schalte ich das DrawImage aus und zeichne nur die neuen Bereiche, geht alles sehr fix. Es liegt also nicht daran das so viele kleine Objekte gezeichnet werden müssen sondern eher an der Fläche..

Gibts da vielleicht doch noch ne Möglichkeit das "DrawImage" zu beschleunigen, ich denke das ist der Flaschenhals..
Kann man da was falsch machen? (falsches Image-Format, was weiß ich.)

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo SirSydom,


g.DrawImage (_picb.Image, x, y);

funktioniert bei mir auch nicht, aber


g.DrawImage ((Image)_picb.Image.Clone (), x, y);

tut es.

Wenn das Bild nur so groß ist, wie die PictureBox und die Verschiebung (x,y) nur gering ist, wird es vermutlich auch anderes kaum schneller gehen. Bei großen Bildern und/oder großen Verschiebungen kann es sein, dass es schellere Möglichkeiten gibt.

herbivore

SirSydom Themenstarter:in
141 Beiträge seit 2006
vor 17 Jahren

meine neue Idee war, das Bild beim Laden komplett zu erstellen.
Also die gesamte Landschaft in en großes Bitmap zeichnen und beim scrollen usw einfach nur Ausschnitte dieses Bildes in die picbox zu zeichnen.

Da meine Karte aber 10001000 groß ist, und in der besten Zoomstufe jedes Feld 5338 Pixel groß ist bekam ich ein Bitmap mit 53000*38000 Pixeln g

Da gabs dann schon ne ArgumentException vom Bitmap Konstruktur.
Trotz 2Gig Ram war das wohl zuviel g

Kein wunder, bei 32bit Farbtiefe wären das ja auch schon 7,5 Gig lol

Erst denken, dann proggen.

I
1.739 Beiträge seit 2005
vor 17 Jahren

Entschuldige die lange Verspätung, zum Glück konnte Herbivore dir inzwischen weiterhelfen.

So allerdings ist dein letzter Lösungsversuch ist auch nicht schlecht (Ansatz Kompletterstellung).
Den musst du nicht gleich verwerfen.

Zu deinem Lösungsansatz mit Kompletterstellung der Karte.

A: Ich würde eine Karte mit der 11 PixelMatrix erstellen, die dürfe auch für 22 Pels genügen(oder auch nicht, wie du magst).

[B: Die KomplettBitmap bereits beim Erstellen aufteilen. Je nach benötigter Zoomstufe eventuell unterschiedliche Kacheln(für unterschiedliche Zoomstufen angepasste Sets) erstellen.
-> Dann ab auf die Festplatte.
C: Diese Segmente zur Laufzeit laden bzw. entladen/disposen. Weg ist das Speicherplatzproblem.

Anmerkung: das If-Konstrukt hält sich in diesem Fall durchaus in Grenzen. Ich schlage ausserdem vor das RescourcenManagement in einem seperaten Thread ablaufen zu lassen.

Oder einfacher gesagt: splitten und auslagern.
Für eine reine Kartendarstellung würde es genügen..

Reine Neugierde: Interessant wären sicher Parameter wie max-Zoom(nicht nur wegen Geschwindigkeit sondern auch Qualität), kleinste Grösse der Bitmapdarstellung(min-BitmapZoom).

QUOTE]Alle kleineren Zoomstufen sind nicht mehr mit Bildern sondern mit verschiedenfarbigen Rechtecken, ähnlich der rechts eingeblendeten Karte.
Die kleinste Zoomstufe soll 1 Pixel pro Feld sein.

Übrigens "Abbildung rechts" konnte ich nicht sehen. Der Link den ich sah ging auf Wiki, da gabs rechts keine Bilder...

Die Sache mit den Farben und/oder Graphiken(vielleicht sollen ja einige sowieso schwarz(welche Farbe immer) sein weil sie im Nebel sind).
Und soll weiterhin heissen: das die Darstellungsform wechselt? Also von "geographisch" auf "politisch"(als Bsp.)? Das könnte so weitere Möglichkeiten aufbohren - die Anforderungen erscheinen weniger resourcenfressend.

Jedenfalls hast richtig erkannt, das allein aus Ressourcengründen unterschiedliche Detaillevels wichtig sind.

Bei den geographischen Darstellungen, wären auch Sachen wie Einheiten/Bautendarstellung interessant, dh ob sowas vorkommen soll.
Das wäre dann ein weiteres Detaillevel.

Bsp:
Civilisation.
Grundaten:
Geländetyp: BitmapSet(Gras, Hügel,Berg, Wüste, Küste etc.)
Geländeeigenschaft: BitmapSet(Wald, Fluss, Dschungel)
Geländeboni:Bitmap/AnimationsSet(Ressourcen wie Kohle, Eisen etc.)
Städte:BitmapSet(nach Grösse, Fortschritt, Kultur und so)
Geländeverbesserungen:BitmapSet(Strassen, Felder, Minen etc)
Einheiten:Bitmap/Animationsset
Beim rauszoomen werden nach und nach Details ausgeblendet.

Diese Trennung in Typen hält den Speicherverbrauch relativ klein, da sich die Felder aus ihnen zusammensetzen(Ein Feld baut sich in oben genannter Reihenfolge auf) erfordern pro Feld allerdings mehrere Zeichenoperationen.
Bei Performancefragen muss man dann anders rangehen, sicher ergeben sich dann auch Limits für die spielbare Darstellung. Gegen einen Switch auf eine andere Darstellung bei kleineren Zoomstufen spricht dann nichts/ist dann halt auch eher zwingend(ich wiederhol mich wohl). Es wird auch irgendwie oft auf die Platte zugegriffen...

Anderes Bsp:
Strategiespiel der anderen Art(mir fällt gerade kein Name ein).
Grundlegende Geländetypen, ein paar Rescourcen keine oder wenig Einheiten.

Möglicherweise vordefinierte Regionen/Länder die den Eigentümer wechseln.
Das könnten dann andere(wesentlich einfachere) Darstellungsformen sein.

Hab ich nur der Vollständigkeit halber erwähnt.

Vermutlich wirst du wohl je nach Zoom die Darstellungsform wechseln müssen.

Es gibt also die Möglichkeiten die Karte komplett zu erstellen oder für jede Darstellung neu zusammenzusetzen. Beide Möglichkeiten haben ihre Vor/Nachteile sowie Grenzen. Ich empfehle den Einsatz beider Möglichkeiten(sinnvoll nach Zoomstufe) bzw. Kombination.

Soll es bei deinem Spiel sowas wie bewegliche Einheiten, Bauten usw. geben, oder ne reine Karte mit lediglich selektierbaren Flächen?