Hello! I’m developing in VB6, with the latest version v5.1.1.
I’m trying to draw a circle of a certain radius in meters. The documentation specifies that the radius in the DrawCircle call is in pixels, however this doesn’t seem to be the case, since for a certain fixed value, the size of the circle changes with the zoom level, suggesting that the radius is determined in some unit related to real world units (meters, feet, minutes, not sure which one actually.) Does anyone know whether the documentation is wrong, I’m doing something incorrectly, or what is happening here at all?
Thank you very much!
Hello @pablodaniel
Perhaps the documentation is a little misleading. It all depends upon what you specify when you call NewDrawing, to create the drawing layer. There you will specify the spatial reference for the drawing, being either pixels or map units. That setting will apply for all drawing that takes place in that drawing layer.
As such, the value you specify for radius should be in the current map units, which could be feet, meters, degrees, etc. If you don’t know for sure, you can call AxMap.MapUnits, which returns an enumeration tkUnitsOfMeasure. See also, Utils.ConvertDistance
.
I hope that clears things up. I will look into updating the documentation.
Regards,
Jerry.
Hi @jerryfaust!
Thanks for the help! You’re right, I’m setting dlSpatiallyReferencedList on the drawing creation so I should have caught that. I’m facing another problem now: no matter what I set AxMap.MapUnits to, the size of the circles wont change on the map when I redraw.
I’m actually setting Map1.MapUnits, where Map1 is the name of the mapwingis component in the form I’m using in VB6. Is that correct or should I set the MapUnits property somewhere else?
Sorry, my friend. I may have misled you.
What we’re really interested in are the units of spatial reference, being AxMap.GeoProjection.LinearUnits. These are what are used internally when drawing shapes that are ‘spatially referenced’. The map units are more for display purposes, not the internal conversions.
You can’t change the internal LinearUnits; they are set either before you load layers, or based on the layers you load (depending upon your settings). So to specify the proper radius, you should convert from your desired units of measure to the internal LinearUnits, using Utils.ConvertDistance, something like:
Dim m_Utils As New Utils()
Dim radius As Double = 50 ' meters
' after calling ConvertDistance, radius will be in the proper units
m_Utils.ConvertDistance(tkUnitsOfMeasure.umMeters, Map1.GeoProjection.LinearUnits, radius)
' draw circle
Map1.DrawCircleEx(handle, x, y, radius, color, fill)
I believe that should do it.
Jerry.
Thanks again for all the help Jerry!
The code is working, as in changing the units does change the size of the circle now. However, the circle in meters I’m drawing should have a radius of 200m, but when measured in the map (roughly measured using reference points from the map tiles), it has as a radius of about 170 meters, which means it’s 15% smaller than it should be. Any ideas why I could be seeing that difference?
Hello.
Not sure what might be going on. If you don’t mind posting the code that does the calculation and draws the circle, I could have a look.
Sure, here is the meat of the code:
*** On form load: ***
Map1.Projection = tkMapProjection.PROJECTION_GOOGLE_MERCATOR
myId = tkTileProvider.ProviderCustom + 2
'Local server with openstreetmap tiles:
ans = Map1.Tiles.Providers.Add(myId, "Localhost Provider", "http://localhost/hot/{zoom}/{x}/{y}.png", tkTileProjection.SphericalMercator, 0, 16)
Map1.Tiles.ProviderId = myId
*** On the draw function ***
Dim m_Utils As New Utils
Dim valDist As Double, visDist As Double
Map1.ClearDrawings
Handle = Map1.NewDrawing(tkDrawReferenceList.dlSpatiallyReferencedList)
Map1.DegreesToProj sourceLon, sourceLat, X, Y
visDist = 3000
valDist = 200
ans = m_Utils.ConvertDistance(tkUnitsOfMeasure.umMeters, Map1.GeoProjection.LinearUnits, valDist)
Map1.DrawWideCircle X, Y, valDist, RGB(120, 0, 0), False, 4
ans = m_Utils.ConvertDistance(tkUnitsOfMeasure.umMeters, Map1.GeoProjection.LinearUnits, visDist)
Map1.DrawWideCircle X, Y, visDist, RGB(0, 120, 0), False, 4
Thanks!
1 Like
What you’ve got is fine. I set up a simple (very similar) test, and realized that the ConvertDistance doesn’t account for the distortions of Web Mercator. The result comes back simply as 200, since both units of measure are in meters. But meters in Web Mercator are only meters at the equator.
If I create a layer in UTM zone (meters) and add a 200 meter radius circle, then add the layer to the map, the layer is properly reprojected to the Web Mercator projection and is the radius correct size. So it is handled properly on the reprojection, but not on the simple distance conversion.
I’m looking to see if the map has a built-in converter or if you will have to apply a conversion, similar to https://gis.stackexchange.com/questions/93332/calculating-distance-scale-factor-by-latitude-for-mercator. But I tried this and it didn’t seem to work. I’ll keep poking around and you let me know if you discover anything.
Regards,
Jerry.
Hello again.
I just reviewed this with a clear head. I was testing in VB.NET, not VB6, and I remembered that the .NET Math.Cos() function assumes Radians, and I was handing in Degrees. Once I applied the proper factor, the result was correct.
So, based on your current latitude, multiply your desired radius (in meters) by [1 / Cos(latitude)], or
mercatorRadius = meters / Cos(latitude)
Then you can draw a circle of the proper size using the value of mercatorRadius.
Hello,
That did the trick! I really should have thought of that myself, I do that conversion when manually calculating distances in my code. It’s drawing the circle with the correct radius now. Thanks!
By the way, is there any simple way to add transparency to the circles drawn by DrawCircle? If so I haven’t found it yet in the documentation.
Thanks again for all the help!
Sorry, no. The drawing layer does not support transparency.
You could consider adding an actual layer, and setting it to Volatile, which renders more quickly on top of the ‘data’ layers. As a standard layer, you have much more control over rendering.
Regards.
Jerry.