Retrieving cursor location (In pixels) from non-rectified image

Hello, I am new to this forum, but I have been working with MapWinGIS for the past few months and I have to say, the features of this software are incredible.

I am creating a mapping application that takes in plain .JPGs, and allows a user to geo-rectify, so that the user may plot information in real time from a GPS instrument. I can draw

the image no problem. I can see the cursor coordinates in the top right of the window. I cannot retrieve those coordinates so that I can use them for my translation calculations (affine transformation). I have seen a similar thread here, but it appears their image was already rectified to give the Lat/Long. (this is not yet the case).

    Label5.Text = AxMap.MousePosition.X
    Label6.Text = AxMap.MousePosition.Y
    XMapPixel.Text = AxMap.MousePosition.X
    YMapPixel.Text = AxMap.MousePosition.Y

    'This converts mouse position X/Y to Lat/Long
    AxMap1.PixelToProj(AxMap.MousePosition.X, AxMap.MousePosition.Y, mapX, mapY)

    'displays lat/long in textboxes with 6 decimal places
    Label5.Text = Format(mapX, "###.######")
    Label6.Text = Format(mapY, "##.######")

axmap.mouseposition.x / y seems to give the mouse cursor location within the application window itself, not the mapwinGIS window. As a result, and a result I think of there not being a worldfile(yet), the coordinates displayed in label 5/6 from the above snippet are also useless. The only coordinates that would be useful are the ones already on the screen, but I cannot seem to access them.

I have also tried using the Axmap1.latitude/Axmap1.Longitude calls, but they return nothing.

Below is the code snippet showing how I add the image. I am also setting the originalXllCenter and YllCenter so that I can make the top left corner the picture origin. this seems to work, as I can reference the coordinates within the map window, and the center of the top left pixel gives me a 0,0 reading.

    Dim imgX, imgY As Double
    Dim sfWorld As New MapWinGIS.Image
    sfWorld.Open("C:\Users\ericp\Desktop\market.jpg")
    AxMap1.AddLayer(sfWorld, True)

    imageH = sfWorld.OriginalHeight         'these two lines get the image height and width
    imageW = sfWorld.OriginalWidth
    imgX = 0                                'these two lines set where the image is drawn
    imgY = (imageH - 1)                     'in this case, i want it to have an origin in the center of the top-left pixel
    sfWorld.OriginalXllCenter = imgX
    sfWorld.OriginalYllCenter = (imgY * -1)

In version 5.2, what is the best way of retrieving an images coordinates that are displayed within the map window?

Welcome, Eric to this community.

You can have a look at the ImageRegistration plugin for MapWindow5.

It does the same as what you want to do.

Thank you very much for pointing me in that direction. I will take a look at it. I have three follow up questions.

  1. should I need to go another route, are the coordinates that are shown within the map window accessible via code?

  2. How do I add this plug in? Do I just copy the files in to my c:\Dev\mapwingis directory?

  3. I’m a dirty VB.NET programmer as this is for a scientific application, coding is a necessity, a means to an end, not really my day job. Knowing that, will I be able to access this new plugin using VB?

I appreciate your help. I normally stay away from forums, but I have been bashing my head against the wall for a week on this and I have to say this forum seems to be my only hope. help me ob…well you know the rest.

Upon further review, I think I misunderstood. It looks as though the image registration plugin is for the mapwindow5 software. I am not sure if that solves my problem. I am using the MapWinGis OCX with visual studio to write my own application.

I am amazed that I cannot retrieve data from the axmap1.Latitude/longitude calls. Could these just be broken in my version (5.2). Should I try to go back to an earlier build?

Thanks again everybody / anybody…

Hello Eric.

Agreed, I just tried the AxMap1.Latitude and Longitude, and I’m getting zeroes. I’ll try to verify what’s going on, and submit a fix if necessary.

As an alternative, the coordinates should be available in the MouseMove event as pixel positions. You can then use the PixelToProj method to derive the coordinates based on the current map projection.

Thank you, and Regards,
Jerry.

Follow-up:
There must be a projection set in the Map :-/

I threw together a simple test app, but Projection was set to None. As soon as I set

AxMap1.Projection = tkMapProjection.PROJECTION_WGS84

I started getting valid DMS coordinates in my MouseMove event.

So you want to either set a specific map projection, or let the map projection be set by the layers you add (see GrabProjectionFromData).

Hope that helps.

Thanks for the quick reply!

Here’s a screen grab of my test application.

Private Sub AxMap1_MouseMoveEvent(sender As Object, e As _DMapEvents_MouseMoveEvent) Handles AxMap1.MouseMoveEvent
    Dim mapX, mapY As Double
    Dim CoordX, CoordY As Double
    CoordX = AxMap1.Latitude
    CoordY = AxMap1.Longitude
    'This adds the raw mouse pixel position to a variable or label
    XMapPixel.Text = AxMap.MousePosition.X
    YMapPixel.Text = AxMap.MousePosition.Y

    'This converts mouse position X/Y to Lat/Long
    AxMap1.PixelToProj(AxMap.MousePosition.X, AxMap.MousePosition.Y, mapX, mapY)


    Label5.Text = Format(mapX, "###.######")
    Label6.Text = Format(mapY, "##.######")

    Label13.Text = CoordX
    Label14.Text = CoordY

End Sub

and here is my test Mousemove event code.

I was already setting a projection in the form1_load() Sub. precisely as you suggested.

  1. using the axmap.mouseposition.X / Y method, I get the data you see in the textboxes labeled X pixel / Y pixel. these coordinates appear to be pixel coordinates within the screen itself. The number does change when I resize or move the application window. I believe that this method is currently returning the screen pixel location (which can change based off application window size AND location.

  1. the PixeltoProj method is returning a puzzling value for me. it would make sense that to do this accurately, you would need to set a projection. In the above image, I have just zoomed in to a generic spot on the map. In this case, Boston. The 4 labels on the top left are (first two get data from the PixeltoProj method, the second two get data from the simple latitude/longitude calls saved to coordX/coordY.

While moving the mouse around, the PixeltoProj coordinates update as expected. give accurate data. no issues. the axmap1.Longitude/latitude calls do not update, unless you adjust a zoom level, and then the instant you move the mouse, it updates, once, and then stops. BUT, the data is accurate to the location/projection being used.

  1. The ANOMOLY!

Once I click my image test button, and draw the jpeg, (which is the first image in this post), you lose the map as the background behind the image. makes sense, its just an image. there’s no worldfile (.JGW). There’s no way to place it. So, the coordinates shown within the map window, revert to pixel location (within the image itself) which means you can locate a point in that image, no matter the zoom level or location of the image. origin (0,0) by default the lower left corner, all the way to the upper right corner (image width, imageheight).

BUT…you lose any data from the Axmap1.Longitude/Latitude calls. Could the projection change/get lost when I draw the image?

Also…The PixeltoProj data gets wonky to say the least.

Thoughts?

Hello Eric.

I just looked again at the documentation for Latitude and Longitude. They return the latitude and longitude of the center of the screen. I don’t know the history of these properties, or why they are implemented this way, but it explains why you only get one initial value when changing the map extents. So for now, I’d say just use the pixel position transformation in the MouseMove event.

Regarding some of the other issues you raise, I will not be able to review them until this evening at best.

Regards,
Jerry.

Did some further testing.

-adding an image that is not rectified seems to remove the projection which would make sense.

-adding a sub that fires when a layer is added, and then manually assigning a projection makes for some bizarre data. the software is trying to work with what its’ got, which in this case is not much.

-I wish I knew where the coordinates on the map window receive their data. that’s the precise data I need.

I downloaded the source code from Git for the 5.3 release. Ill pull this if having a snippet of Src code is against forum rules. just let me know.

After doing some digging, I found the Map_Dynamic.CPP file. within that file is a “Draw Coordinates” Sub routine. starts on Line 225.

// ****************************************************************
//		DrawCoordinates()
// ****************************************************************
void CMapView::DrawCoordinates(Gdiplus::Graphics* g) 
{
	if(HasDrawingData(tkDrawingDataAvailable::Coordinates)) 
	{
		POINT p;
		if (GetCursorPos(&p))
		{
			ScreenToClient(&p);
			double x = p.x, y = p.y;
			double prX, prY;
			PixelToProjection(x, y, prX, prY);

			bool canUseDegrees = _transformationMode == tmWgs84Complied;
			if (_transformationMode == tmDoTransformation && (_showCoordinates == cdmDegrees || _showCoordinates == cdmAuto))
			{
				IGeoProjection* p = GetMapToWgs84Transform();
				if (p) {
					VARIANT_BOOL vb;

					// in some cases transform can change values on failure
					// therefore we shall use temp variables to preserve them
					double tempX = prX;
					double tempY = prY;

					p->Transform(&tempX, &tempY, &vb);
					if (vb) 
					{
						canUseDegrees = true;
						prX = tempX;
						prY = tempY;
					}
				}
			}

			if (_showCoordinates == cdmDegrees && !canUseDegrees) {
				// can't display degrees
			}
			else {
				CStringW s;
				if (canUseDegrees) 
				{
					CStringW lat = AngleHelper::FormatAngle(prY, _showCoordinatesFormat, 3, false);
					CStringW lng = AngleHelper::FormatAngle(prX, _showCoordinatesFormat, 3, false);

					s.Format(L"%s: %s; %s: %s", m_globalSettings.GetLocalizedString(tkLocalizedStrings::lsLatitude), lat,
						m_globalSettings.GetLocalizedString(tkLocalizedStrings::lsLongitude), lng);
				}
				else
				{
					s.Format(L"x=%.2f; y=%.2f", prX, prY);
				}
				Gdiplus::PointF point(0.0f, 0.0f);
				Gdiplus::RectF rect;
				
				g->MeasureString(s, s.GetLength(), _fontCourier, point, Gdiplus::StringFormat::GenericDefault(), &rect);
				if (rect.Width + 15 < _viewWidth)		// control must be big enough to host the string
				{
                    // position the text
                    point.X = _viewWidth - rect.Width - 7.0f;
                    point.Y = 7.0f;
                    if (_showCoordinatesBackground)
                    {
					    // draw a white box behind the coordinates
					    Gdiplus::Rect r(_viewWidth - rect.Width - 7.0f, 7.0f, rect.Width, rect.Height);
					    g->FillRectangle(&GetMeasuringBase()->_whiteBrush, r);
                        // with white background, we don't need shadowed text
                        g->DrawString(s.GetString(), s.GetLength(), _fontCourier, point, &GetMeasuringBase()->_textBrush);
				    }
                    else
                    {
                        // default display, shadowed text
                        DrawStringWithShade(g, s, _fontCourier, point, &GetMeasuringBase()->_textBrush, &GetMeasuringBase()->_whiteBrush);
                    }
                }
			}
		}
	}
}

As Somebody that is NOT GREAT at programming, this appears to be a bag of snakes that I can only begin to straighten out. And like Indiana Jones, I hate snakes…

Entering arguments:

  1. We know ONE of these conditional statements produces the correct information. We can see the “Draw Coordinates” Sub do this in the pictures I’ve previously posted.
  2. If the program can draw coordinates that equate to a ( pixel , pixel ) location within the image (where zoom, application screen size and location, and image location within the map window) all have no effect on the outcome. then it’s safe to postulate the snagging of said information (maybe).

looking at this code, and assuming that adding an image cancels out the current map projection to “None”. Which statement do you think is producing the mouse cursor location?

Holy Cow, I think I figured it out. It was a combination of things, but Thank you Jerry!! it was actually a post on a different thread regarding a similar issue. The pixeltoproj method is exactly what I needed to use. The issue?! The entering arguments.

In my case,

AxMap1.PixelToProj(e.x, e.y, coordx1, coordy1)

This is what I needed… Simple e.x/e.y inputs gives the exact output that I required. albeit to a level of precision that I and most likely nobody would ever need. This is wonderful and mind numbing all the same. I thank everyone here who helped out. you guys sent me down the rabbit hole, made me look at things I wouldn’t have otherwise. so I tip my hat to you guys.

I’m glad you made some progress.
I mentioned the ImageRegistration plugin not to use it directly in your application but to look at the code and understand how it works because it is doing more or less the same.

PMeems,

I will take a look at the code and see if I can use it as a template for my routine. I already have a pretty good concept of what to do to perform the calculations, but seeing how other people do it always helps.

thanks!