Reputation: 731
I'm wondering if anyone can help me with this or at least provide pointers in the right direction. I can post code if required however, due to the nature of the question, there is a lot of it and hence why I haven't so far.
I have a custom control which represents a "map". On this "map" I can draw specific glyphs at specific latitude and longitude's. I use GPS behind the scenes to obtain a geographic fix location which I then feed into the map as its origin position.
All objects drawn to the map have their lat/long positions converted to easting and northings (using an algorithm similar to the Google Maps/Bing projection) before being converted to screen pixels.
I take the centre of my "map" control client region as the reference screen position. When the "map" is panned, I store the delta mouse movement as an offset which when added to the reference position, gives me the location to start drawing my origin grid (this is also where the GPS position links in).
I hope this is making sense so far...
Now, all works well so far - I can draw objects at specific latitude and longitudes and they all appear in their correct locations relative to the centre of the origin grid.
The issue which I can't seem to get my head around is how to zoom the map and focus on a specific area - like when using Google Maps/Google Earth, the position underneath the cursor at the point of zooming stays the same. Crudely, I use a zoom system which just increases or decreases the number of metres represented by 100 screen pixels (I'd like a more logarithmic style zoom but that will come later).
What happens when I zoom in is that zooming always keeps my grid origin in the same position (this is because I use an offset for panning the map - and the offset isn't affected by zoom) however I have no idea how to think through the more correct zoom system.
I appreciate that this is a lot of text with no code - I can post code but like I said, there is a heck of a lot of it! I'm also sure that I've not explained my scenario very well but I'd appreciate any help at all.
Upvotes: 0
Views: 948
Reputation: 43659
All calculations are preferably done in GPS units, and conversions to device units should be the very last step. With this in mind, the following design should resolve your problem, with the assumption that you can store latitude and longitude in a float type:
type
TMapControl = class(TCustomControl)
protected
procedure Paint; override;
public
Glyph: TBitmap;
//These are known, in GPS-coördinate units:
MapRect: TRectF;
ZoomFactor: Single;
ZoomOrigin: TPointF;
GlyphOrigin: TPointF;
end;
procedure TMapControl.Paint;
var
ZoomWidth: Single;
ZoomHeight: Single;
ZoomRect: TRectF;
Scale: Single;
GlyphPoint: TPoint;
begin
// Calculation in GPS units:
ZoomWidth := MapRect.Width * ZoomFactor;
ZoomHeight := ZoomWidth * ClientHeight / ClientWidth;
ZoomRect.Left := ZoomOrigin.X - ZoomWidth / 2;
ZoomRect.Top := ZoomOrigin.Y - ZoomHeight / 2;
// Not required for calculation, but for future convenience:
ZoomRect.Width := ZoomWidth;
ZoomRect.Height := ZoomHeight;
// Calculation in device units:
Scale := ZoomWidth / ClientWidth;
GlyphPoint.X := Round((GlyphOrigin.X - ZoomRect.Left) / Scale);
GlyphPoint.Y := Round((GlyphOrigin.Y - ZoomRect.Top) / Scale);
Canvas.Draw(GlyphPoint.X - Glyph.Width div 2,
GlyphPoint.Y - Glyph.Height div 2, Glyph);
end;
The zoom factor is the percentage of the part of the total map being viewed. The scale factor converts the size of that portion to the size of your control.
Now the above code has some assumptions, most notably that the zoom origin and the zoom factor are known. Also, the origin of the map is considered to be (0, 0), which is not strictly required, but it keeps calculations easy and is practical too. If these are not the case, that I suggest you mimic the above or redesign what should be considered input and what be output. Or you need to explain better, wíth code, which conversions and calculations you are already doing. (You do not need to post all code for that, just strip to the absolute essential.)
Upvotes: 1