(Gelöst)Pixel auf Image in Scrollbox setzen-falsche Position

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Antworten
GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

(Gelöst)Pixel auf Image in Scrollbox setzen-falsche Position

Beitrag von GU_Meyer »

Hallo,
für eine Geocaching-Software brauche ich eine Kartendarstellung (die Vorstufen dazu sind http://www.lazarusforum.de/viewtopic.php?f=25&t=8844 und viewtopic.php?f=25&t=8964 gewesen. Das funktioniert auch beides sehr zu meiner Zufriedenheit und Erwartung.
Allerdings brauche ich jetzt einen Denkanstoss für folgendes: Nach Eingabe von GPS-Koordinaten werden diese in Pixel-Koordinaten (x,y) umgerechnet. Das funktioniert, abgesehen von leichten Rundungsfehlern einwandfrei. Jetzt befindet sich meine Karte (eine PNG-Datei) in einem TImage und dieses wiederum in einer TScrollbox. Aber wenn ich diese Koordinaten nun einzeichnen lasse (bzw. ich setze ein TShape mit CacheAbstUmkreis.Left und CacheAbstUmkreis.Top auf diese Werte, dann liegt es ein gutes Stück neben den vorgesehenen (und durch einen eingezeichneten Referenzpunkt auf der Karte auch deutlich sichtbaren) Koordinaten.
Mein Verdacht ist, dass die Umrechnung der Koordinaten auf den Clientbereich der Scrollbox nicht funktioniert.
Ich versuche mal, die relevanten Routinen hier einzufügen. Außerdem hänge ich einen Screenshot an, der das Problem hoffentlich zeigt

Code: Alles auswählen

procedure TgcisMainForm.gcisWerkzeugeQuickShowkoordsClick(Sender: TObject);
var mapKoordsPxX, mapKoordsPxY : integer;
    QuickKoordsLon,QuickKoordsLat : real;
    SetzPunkt : TPoint;
begin
  if ctQuickShowKoordsform.ShowModal = mrOk then
  begin
// erstmal die Koordinaten holen
    QuickKoordsLon:=ctQuickShowKoordsform.ctqskLaenge// sind noch GPS-Koordinaten, allerdings berets eine real-Zahl
    QuickKoordsLat:=ctQuickShowKoordsform.ctqskBreite;
// Nach der Berechnung der Position auf der Karte ...
    CalcPointAsPixelFromKoords(gcis_map_KarteWertLinks,gcis_map_KarteWertOben,QuickKoordsLon,QuickKoordsLat,mapKoordsPxX, mapKoordsPxY); // Umrechnung auf Pixel-Koordinaten
{ ----> Ich vermute den Fehler}
    SetzPunkt.x:=mapKoordsPxX;
    SetzPunkt.y:=mapKoordsPxY;
    SetzPunkt:=gcisMainScrollBox.ScreenToClient(SetzPunkt);
{<----- in diesem Abschnitt}
// ...kann dieser Punkt eingetragen werden
    SetzePunktAufKarteMitKoordinaten(SetzPunkt.x,SetzPunkt.y);
  end// if ctQuickShowKoordsform.ModalResult = mrOk
end// procedure TgcisMainForm.gcisWerkzeugeQuickShowkoordsClick

Code: Alles auswählen

 
procedure TgcisMainForm.SetzePunktAufKarteMitKoordinaten(XPixel, YPixel: integer);
var CacheAbstUmkreis : TShape;
    CacheIcon        : TShape;
    MousePoint       : TPoint;
    CacheIconUmkreisGroessePixel : integer;
    CacheAbstUmkreisGroessePixel : integer;
    CacheIconGroessePixel        : integer;
begin
  CacheAbstUmkreisGroessePixel:=radius_DistCachesBoxes;  // Konstante
  CacheAbstUmkreis:=TShape.Create(self);
  CacheAbstUmkreis.Caption:=txt_dbtemp_GCCode+IntToStr(FCacheKreisIndex);   // txt_dbtemp_GCCode ist eine Konstante
  CacheAbstUmkreis.Shape:=stCircle;
  CacheAbstUmkreis.Width:=CacheAbstUmkreisGroessePixel;  // Programm-interne Konstante
  CacheAbstUmkreis.Height:=CacheAbstUmkreisGroessePixel;
  CacheAbstUmkreis.Pen.Color:=clBlack;
  CacheAbstUmkreis.Pen.Style:=psDot;
  CacheAbstUmkreis.Brush.Style:=bsClear;
  CacheAbstUmkreis.Left:=XPixel - (CacheAbstUmkreisGroessePixel div 2);
  CacheAbstUmkreis.Top:=YPixel - (CacheAbstUmkreisGroessePixel div 2);
  CacheAbstUmkreis.Parent:=gcisMainScrollBox;
  CacheAbstUmkreis.OnClick:=@ShapeClick;
  CacheAbstUmkreis.BringToFront;
  inc(FCacheKreisIndex);
end// procedure TgcisMainForm.SetzePunktAufKarteMitKoordinaten   

Code: Alles auswählen

procedure CalcPointAsPixelFromKoords(mapLeftLon, mapToplat, latdec, londec : real; var pxX,pxY : integer);
var
  KoordDistX, KoordDistY : real;
begin
// Abstände berechnen
    KoordDistX:=CalcDistanceDecimalKoordsInKm(mapLeftLon,mapToplat,londec,mapToplat)// Berechnet den Abstand der beiden Koordinatenpaare (GPS-Koordinaten als real-Zahlen) in km
    KoordDistY:=CalcDistanceDecimalKoordsInKm(mapLeftLon,mapToplat,mapLeftLon,latdec);
    KoordDistX:=KoordDistX * 1000// Um den Abstand
    KoordDistY:=KoordDistY * 1000// in Metern zu haben
// Abstände in Pixel umrechnen (über gcis_map_KartePixelProMeterBreite und gcis_map_KartePixelProMeterHoehe
  pxX:=round(KoordDistX * gcis_map_KartePixelProMeterBreite)// gcis_map_KartePixelProMeterBreite wird über das Verhältnis von Kartenbreite in km zu Pixelzahl (KarteImage.Width) berechnet
  pxY:=round(KoordDistY * gcis_map_KartePixelProMeterHoehe);
end// procedure CalcPointAsPixelFromKoords


Hinweis: Bei einer solchen Karte handelt es sich um einen (im Moment) ca.9km breiten und 11km hohen Ausschnitt (2000x2300 Pixel).

Über Denkanstösse würde ich mich sehr freuen...Vielen Dank und
Gruss
GU_Meyer
Dateianhänge
Karte-mit-Fehlerdarstellung.png
Zuletzt geändert von GU_Meyer am Mo 31. Aug 2015, 07:01, insgesamt 1-mal geändert.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von Michl »

Mit ScreenToClient setzt du einen Punkt, der in Abhängkeit der Position deines Formulars auf dem Screen berechnet wird. Versetzt du dein Formular auf dem Monitor dürfte sich die Abweichung des Punktes ebenfalls mit verändern.

Wenn das TImage den Clientbereich der Scrollbox einnimmt (Align vom TImage steht auf alClient oder Anchors sind entsprechend gesetzt) kannst du die Umrechnung (ScreenToClient) einfach weglassen, da mit der Zuweisung CacheAbstUmkreis.Parent:=gcisMainScrollBox; die TShapes die TScrollbox als Parent bekommen (die TShapes werden somit relativ zum Parent (Scrollbox) ausgerichtet).

Eine Umrechnung muss nur gemacht werden, wenn die TShapes an einem anderen Control, an der Maus, an dem Screen oder sonstwie ausgerichtet werden sollen.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von GU_Meyer »

Michl hat geschrieben:Mit ScreenToClient setzt du einen Punkt, der in Abhängkeit der Position deines Formulars auf dem Screen berechnet wird. Versetzt du dein Formular auf dem Monitor dürfte sich die Abweichung des Punktes ebenfalls mit verändern.

ja, das habe ich eben getestet und gemerkt. Ok, ist nicht das, was ich wollte. :|
Michl hat geschrieben:Wenn das TImage den Clientbereich der Scrollbox einnimmt (Align vom TImage steht auf alClient oder Anchors sind entsprechend gesetzt) kannst du die Umrechnung (ScreenToClient) einfach weglassen, da mit der Zuweisung CacheAbstUmkreis.Parent:=gcisMainScrollBox; die TShapes die TScrollbox als Parent bekommen (die TShapes werden somit relativ zum Parent (Scrollbox) ausgerichtet).

Das sieht besser aus. Jetzt liegt das CacheAbstUmkreis-Shape zwar immer noch weit daneben, aber ich vermute hier mal ganz stark, dass das an Rundungs- und evtl. sogar gröberen Rechenfehlern von mir liegt. Da muss ich nochmal genauer recherchieren, wie ich Karten mit bekannten (also über GPS-Koordinaten) Eckpunkten auf Pixel-werte umrechnen kann - ich fürchte, dass diese Umrechnung (also entwder die procedure CalcPointAsPixelFromKoords oder vorher schon meine Skalierung) nicht stimmt.
Michl hat geschrieben:Eine Umrechnung muss nur gemacht werden, wenn die TShapes an einem anderen Control, an der Maus, an dem Screen oder sonstwie ausgerichtet werden sollen.

Danke für die Erklärung.
Gruss
GU_Meyer

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von wp_xyz »

mapCoordsPxX und mapCoordsPxY sind Pixel auf der Karte, also auf dem Image, nicht auf der Scrollbox. Du musst also noch den Unterschied zwischen Image.TopLeft und Scrollbox.TopLeft korrigieren.

GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von GU_Meyer »

wp_xyz hat geschrieben:mapCoordsPxX und mapCoordsPxY sind Pixel auf der Karte, also auf dem Image, nicht auf der Scrollbox. Du musst also noch den Unterschied zwischen Image.TopLeft und Scrollbox.TopLeft korrigieren.

Ich hatte gedacht, wenn ich,
Michl hat geschrieben:Wenn das TImage den Clientbereich der Scrollbox einnimmt (Align vom TImage steht auf alClient oder Anchors sind
setze, ist dieser Unterschied nicht mehr vorhanden? Da ich beim Starten Image.Left und Image.Top jeweils auf 0 setze, weiß ich nicht, wo ein solcher Unterschied überhaupt entstehen kann.

EDIT:
Aus dem gcisMainForm.onShow rufe ich u.a. dies hier auf:

Code: Alles auswählen

procedure TgcisMainForm.KarteLaden(KarteBildDateiNameStr: string);
begin
  gcisKarteImage.Picture.LoadFromFile(KarteBildDateiNameStr);
  gcisKarteImage.Width:=gcisKarteImage.Picture.Width;
  gcisKarteImage.Height:=gcisKarteImage.Picture.Height;
 
  gcisKarteImage.AutoSize:=true// sonst sind keine Scrollbalken vorhanden und Scrollen geht nicht
 
  gcisMainScrollBox.HorzScrollBar.Range:=gcisKarteImage.Width;
  gcisMainScrollBox.VertScrollBar.Range:=gcisKarteImage.Height;
 
end// procedure TgcisMainForm.KarteLaden     


Gruss
GU_Meyer



Gruss
GU_Meyer

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von Michl »

GU_Meyer hat geschrieben:Jetzt liegt das CacheAbstUmkreis-Shape zwar immer noch weit daneben

Versuch doch mal die Extremwerte (Koordinaten(0, 0) und Koordinaten(Karte.xMax, Karte.yMax)) einzugeben und zu debuggen. Normalerweise müsste dann auch die Punkte (0, 0) und (gcisKarteImage.Width, gcisKarteImage.Height) herauskommen:

Code: Alles auswählen

procedure TgcisMainForm.gcisWerkzeugeQuickShowkoordsClick(Sender: TObject);
var mapKoordsPxX, mapKoordsPxY : integer;
    QuickKoordsLon,QuickKoordsLat : real;
    SetzPunkt : TPoint;
begin
  if ctQuickShowKoordsform.ShowModal = mrOk then
  begin
    QuickKoordsLon:=ctQuickShowKoordsform.ctqskLaenge
    QuickKoordsLat:=ctQuickShowKoordsform.ctqskBreite;
 
    CalcPointAsPixelFromKoords(gcis_map_KarteWertLinks,gcis_map_KarteWertOben,QuickKoordsLon,QuickKoordsLat,mapKoordsPxX, mapKoordsPxY);
    SetzePunktAufKarteMitKoordinaten(mapKoordsPxX, mapKoordsPxY)//hier BreakPoint setzen und Werte von mapKoordsPxX und mapKoordsPxY anschauen
  end;
end;

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von GU_Meyer »

Michl hat geschrieben:
GU_Meyer hat geschrieben:Jetzt liegt das CacheAbstUmkreis-Shape zwar immer noch weit daneben

Versuch doch mal die Extremwerte (Koordinaten(0, 0) und Koordinaten(Karte.xMax, Karte.yMax)) einzugeben und zu debuggen. Normalerweise müsste dann auch die Punkte (0, 0) und (gcisKarteImage.Width, gcisKarteImage.Height) herauskommen:

Code: Alles auswählen

procedure TgcisMainForm.gcisWerkzeugeQuickShowkoordsClick(Sender: TObject);
var mapKoordsPxX, mapKoordsPxY : integer;
    QuickKoordsLon,QuickKoordsLat : real;
    SetzPunkt : TPoint;
begin
  if ctQuickShowKoordsform.ShowModal = mrOk then
  begin
    QuickKoordsLon:=ctQuickShowKoordsform.ctqskLaenge
    QuickKoordsLat:=ctQuickShowKoordsform.ctqskBreite;
 
    CalcPointAsPixelFromKoords(gcis_map_KarteWertLinks,gcis_map_KarteWertOben,QuickKoordsLon,QuickKoordsLat,mapKoordsPxX, mapKoordsPxY);
    SetzePunktAufKarteMitKoordinaten(mapKoordsPxX, mapKoordsPxY)//hier BreakPoint setzen und Werte von mapKoordsPxX und mapKoordsPxY anschauen
  end;
end;

Oh, verfl***... :shock: :shock: ... da scheint der Fehler zu sein....ich übergebe der Umrechnungsroutine für die Abstandsberechnung falsche (vertauschte Koordinaten)...da kann das nichts werden.
Mal sehen, das dauert länger, das zu reparieren...erstmal Dankeschön.
Ich meld' mich, egal was rauskommt.
Gruss
GU_Meyer

GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von GU_Meyer »

Bitte gestattet mir ein Update (auch wenn Selbstzitate nicht so elegant sind):
GU_Meyer hat geschrieben:
Michl hat geschrieben:
GU_Meyer hat geschrieben:Jetzt liegt das CacheAbstUmkreis-Shape zwar immer noch weit daneben

Versuch doch mal die Extremwerte (Koordinaten(0, 0) und Koordinaten(Karte.xMax, Karte.yMax)) einzugeben und zu debuggen. Normalerweise müsste dann auch die Punkte (0, 0) und (gcisKarteImage.Width, gcisKarteImage.Height) herauskommen:

GU_Meyer hat geschrieben:Oh, verfl***... :shock: :shock: ... da scheint der Fehler zu sein....ich übergebe der Umrechnungsroutine für die Abstandsberechnung falsche (vertauschte Koordinaten)...da kann das nichts werden.
Mal sehen, das dauert länger, das zu reparieren...erstmal Dankeschön.
Ich meld' mich, egal was rauskommt.
Gruss
GU_Meyer

Jetzt wirds interessant. Der Tip vom Michl war schon mal gut. Jetzt passen die Positionen für links/oben, links/unten, rechts/oben und rechts/unten. Aber wenn ich nun die ausgemessene Position (der rote Punkt) eingebe, stimmt nur noch die y-Koordinate. Ich hab die Abweichung mal rausgesucht:
X-Wert berechnet: 845Pixel
X-Wert Soll: 1108
Y-Wert berechnet: 1251
Y-Wert Soll: 1266
Aus dieser Abweichung würde ich, ohne das Ergebnis mit den 4 Ecken, schließen, dass mein Skalierfaktor für "Pixel/Meter" in der X-Richtung falsch ist (die Abweichung in Y-Richtung lässt sich evtl. über Rundungsfehler erklären :wink: ). Aber wenn ich die 4 Ecken einbeziehe, dann stimmt der faktor ja wieder. :?
Ich werd' weiter suchen...evlt. hat ja noch jemand ne Idee...

EDIT (20150828-22:10): Die 4 Ecken passen, aber alle anderen Koordinaten zwischendurch liegen falsch (sowohl X- als auch Y-Koordinate). Jetzt verstehe ich nichts mehr....mal sehen, ob ich morgen eine Idee hab.
Trotzdem Danke und
Gruss
GU_Meyer

GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Re: Pixel auf Image in Scrollbox setzen - falsche Position

Beitrag von GU_Meyer »

GU_Meyer hat geschrieben:Bitte gestattet mir ein Update (auch wenn Selbstzitate nicht so elegant sind):
GU_Meyer hat geschrieben:Oh, verfl***... :shock: :shock: ... da scheint der Fehler zu sein....ich übergebe der Umrechnungsroutine für die Abstandsberechnung falsche (vertauschte Koordinaten)...da kann das nichts werden.
Mal sehen, das dauert länger, das zu reparieren...erstmal Dankeschön.
Ich meld' mich, egal was rauskommt.
Gruss
GU_Meyer

Jetzt wirds interessant. Der Tip vom Michl war schon mal gut. Jetzt passen die Positionen für links/oben, links/unten, rechts/oben und rechts/unten. Aber wenn ich nun die ausgemessene Position (der rote Punkt) eingebe, stimmt nur noch die y-Koordinate. Ich hab die Abweichung mal rausgesucht:
X-Wert berechnet: 845Pixel
X-Wert Soll: 1108
Y-Wert berechnet: 1251
Y-Wert Soll: 1266
Aus dieser Abweichung würde ich, ohne das Ergebnis mit den 4 Ecken, schließen, dass mein Skalierfaktor für "Pixel/Meter" in der X-Richtung falsch ist (die Abweichung in Y-Richtung lässt sich evtl. über Rundungsfehler erklären :wink: ). Aber wenn ich die 4 Ecken einbeziehe, dann stimmt der faktor ja wieder. :?
Ich werd' weiter suchen...evlt. hat ja noch jemand ne Idee...

EDIT (20150828-22:10): Die 4 Ecken passen, aber alle anderen Koordinaten zwischendurch liegen falsch (sowohl X- als auch Y-Koordinate). Jetzt verstehe ich nichts mehr....mal sehen, ob ich morgen eine Idee hab.
Trotzdem Danke und
Gruss
GU_Meyer[/quote]

So wie es aussieht, ist der Fehler bzw. das Problem nicht durch Lazarus bzw. meine Berechnung verursacht. Ich hab die Berechnungen händisch durchgeführt und dann mit der Kartendarstellung in einer Bildbearbeitungssoftware verglichen. Selbst da liegen die errechneten Werte für meine Pixelpositionen an anderen Stellen. Damit ist es Lazarus-Problem mehr...ich werde den Thread auf "Gelöst" setzen (bwz. hab ich schon).

Trotzdem nochmal vielen Dank fürs Mitdenken und die guten Vorschläge.
Gruss
GU_Meyer

Antworten