Skip to content
This repository has been archived by the owner on May 9, 2018. It is now read-only.

RMMark, RMPath "vibrate" while the RMMapView is being scrolled #72

Open
mouse4d opened this issue Jul 26, 2012 · 81 comments
Open

RMMark, RMPath "vibrate" while the RMMapView is being scrolled #72

mouse4d opened this issue Jul 26, 2012 · 81 comments

Comments

@mouse4d
Copy link

mouse4d commented Jul 26, 2012

while scrolling the map the RMMarker and RMPath overlay "vibrates", it's like the overlay tries to "catch up" with it's normal position when the map is scrolled. It's just a few pixels, but when zoomed it looks pretty bad. this happens most probably because the -draw() method is called only when the map is moved more than just a pixel.

@incanus
Copy link
Contributor

incanus commented Jul 26, 2012

For RMPath, see #73.

For RMMarker, I haven't seen this. Do you still see it when not using a path/shape with your markers, and if so, when using RMShape instead of RMPath?

@incanus
Copy link
Contributor

incanus commented Aug 11, 2012

I at least can see this now. Will try to address soon.

@incanus
Copy link
Contributor

incanus commented Oct 1, 2012

Assigned to Tender discussion #259.

@cga-F4
Copy link

cga-F4 commented Oct 2, 2012

Hi, I tried to see where this problem comes from.
With high zoom level, we see that the tile layer moves pixel by pixel while the RMMarker moves only 4 by 4 pixel.
I log some info in the function in RMMapView

  • (void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject change:(NSDictionary *)change context:(void *)context
    and we see that we are called each time the tile layer is moved, but the .contentOffset value from the change variable is the same and only changed 4 by 4 pixel. The _mapScroolView.contentOffset follows the same : it does not change pixel by pixel, but 4 by 4 pixel.
    Maybe this is because, with high level zoom, the contentSize and contentOffset are really big value (and there are float), and Apple scrollview does not support accurate move on big big contentOffset/contentSize.

I hope this can help you find a fix for this issue.

@davidovitch1
Copy link

same problem here, any news ?

@cga-F4
Copy link

cga-F4 commented Oct 30, 2012

Since last time, i tried using Alpstein Route Me, and we see the same problem with their example MarkerMurder. When you zoom to max, you see the marker vibrating (in this example, you can set the maxZoom to 22, and on maximum zoom, the markers vibrates much more).
I saw the layer with annotations is not in the RMMapScrollView *_mapScrollView. Would it be a bad idea or lots of work to have the RMMapOverlayView *_overlayView and the _tiledLayersSuperview in the same scrollView ?

@cga-F4
Copy link

cga-F4 commented Oct 31, 2012

I see the problem : when I am on level 19 zoom, and I look to Paris, France, my contentOffset has a value more than 60 000 000. When scrolling, we want to add 1, 2, 3 ... pixels to this value. But due to float precision, 60 000 000 + 1 returns 60 000 000 and 60 000 000 + 3 returns 60 000 004. We have a precision to 4 digit, so we see the annotions move only 4 pixels by 4 pixels. All because contentOffset is a float value (not double). [ By the way, I don't know how the _mapScrollView handles this by itself for the tileLayer which moves perfectly good, maybe the OS computation is in double but we can only access the contentOffset with float precision]
One solution would be to ensure that our contentOffset does not go further than the float precision limit.
From this post : http://stackoverflow.com/questions/1576126/iphone-and-floating-point-math, we can see that if we want a 1 pixel precision, we need to keep contentOffset under approximatively 8 000 000 (log2(8000000) = 22.93 < 23). This explains why we have the problem with big zoom level, and not average zoom level.

@incanus
Copy link
Contributor

incanus commented Oct 31, 2012

Interesting, @cga-F4. That's a great find & this makes sense. I will take a look.

@incanus
Copy link
Contributor

incanus commented Nov 17, 2012

@trasch, do you have any insight into this? I'm wondering if you ever tried the route of making the overlay layer size with the scroll view's content view, instead of making it a scroll layer with annotation corrections like it is now.

@trasch
Copy link
Contributor

trasch commented Nov 22, 2012

I did try it, but I really can't remember what the issue was. Maybe this is not an issue any more, since so many parts of route-me have changed in the meantime. It would certainly make lots of things easier if the overlay would have the size of the content view, maybe we could just try it.

Apart from that I honestly never thought that anyone would use route-me with zoom leves above 18... :)

@psavich
Copy link

psavich commented Nov 25, 2012

Hello there. I'm experiencing the same problem on zoom levels 17 and above.

Here's a demo: https://dl.dropbox.com/u/586782/mapbox-marker-bug.mp4

The problem is definitely related to float precision of contentOffset – like cga-F4 I injected some logging into the value observer, and here's what I got (each line is a 1px movement):

2012-11-25 19:51:16.403 iGIS[98912:c07] ContentOffset: 162256000.000000 83907544.000000
2012-11-25 19:51:16.420 iGIS[98912:c07] ContentOffset: 162256000.000000 83907544.000000
2012-11-25 19:51:16.436 iGIS[98912:c07] ContentOffset: 162256000.000000 83907544.000000
2012-11-25 19:51:16.453 iGIS[98912:c07] ContentOffset: 162256016.000000 83907544.000000
2012-11-25 19:51:16.470 iGIS[98912:c07] ContentOffset: 162256016.000000 83907544.000000
2012-11-25 19:51:16.487 iGIS[98912:c07] ContentOffset: 162256016.000000 83907536.000000
2012-11-25 19:51:16.503 iGIS[98912:c07] ContentOffset: 162256016.000000 83907536.000000
2012-11-25 19:51:16.520 iGIS[98912:c07] ContentOffset: 162256016.000000 83907536.000000

As you can see, on 19 zoom we have a jump of 16px by x, and 8px by y. Each step of zooming out decreases the "jump distance" by factor of 2.

Unfortunately this issue is critical for our project, cause all RMPaths and RMMarkers vibrate really badly in some important use cases.

I see two solutions:

  • unbind annotations from contentOffset and align their position to some more accurate properties.
  • workaround by shifting the center of coordinates somewhere near ourselves, to decrease the value of contentOffset and make it more precise (this is possible in our situation because we work with a single city in our project)

What do you guys think about this stuff?

@zhm
Copy link

zhm commented Nov 27, 2012

+1 to seeing this one fixed. Once this gets fixed I can complete the conversion of 2 apps to this SDK :) This one is just kind of critical because users have maps that are often high resolution satellite imagery.

@cga-F4
Copy link

cga-F4 commented Jan 2, 2013

Hi ! (and Happy New Year)
Is there some news for this issue ? This is critical for us too.

@incanus
Copy link
Contributor

incanus commented Jan 2, 2013

I will be investigating this soon and working with upstream on it. Have a couple ideas here.

@specialunderwear
Copy link

This blog contains a proper solution to the problem: http://www.mlsite.net/blog/?p=1342 for more context, see Outdooractive/route-me#122 (comment)

@incanus
Copy link
Contributor

incanus commented Jan 7, 2013

I'm not sure this does entirely solve the problem, though I have to investigate further. It says:

Note that the content view is set to the size of the entire rendered world; this does not cause out-of-memory problems because the content view does not render any content directly; only those subviews in its visible area are rendered.

Which leads me to believe that we will still have precision problems with higher zoom levels since the effective content view is still dealing in 1:1 pixel sizes with the current method.

@specialunderwear
Copy link

No, the problem you are seeing, is that on high zoom level you need to scroll 10 pixels for a contentOffset change to be fired, because it is assumed you are viewing a zoomed in bitmap. By resetting the zoomlevel back to 1 you will get back the fine grained scroll events.

@incanus
Copy link
Contributor

incanus commented Jan 7, 2013

Ah, interesting.

@specialunderwear
Copy link

Could you keep this ticket updated with progress? I was planning on working on this myself, but it's better to not waste 2 people's time working on the same thing. Or if you want some help, I'm more then happy to chip in :)

@incanus
Copy link
Contributor

incanus commented Jan 7, 2013

Yes, I will. I am working on this combined with improved tile load performance in a hopefully-major (if successful) overhaul of this subsystem.

@incanus
Copy link
Contributor

incanus commented Jan 8, 2013

Based on my testing, this is a limitation in UIScrollView. I'm currently working on some testing that uses a large (> z17) content view, nothing to do with the KVO calls, and its own content view vibrates in this manner on high zoom.

I'm working on this issue in combination with performance work from discussions in Outdooractive/route-me#35 and will probably end up doing something related to not actually having the scroll view content view be 2^zoom * 256 pixels to a side, but rather "faking out" the system in order to keep the content view within reasonable sizes.

@specialunderwear
Copy link

Yes, that is true, because again, it is assumed you are looking at a zoomed in bitmap, where it makes no sense to scroll less then 1 (hugely magnified) pixel. Now if you would have tested the kvo calls as well, you would have noticed the calls will only be triggered by scrolling for the magnified pixel (10 pixels instead of 1). Which still means that resetting the zoom level back to 1 after zooming has completed solved all problems. Also your problem IS the kvo calls because you are updating the position of the markers based on kvo events (thevmarkers are not even inside the scroll view). You can actually test this by zooming in heavily and scroll for less then 10 pixels and you will see no kvo events triggered untill you scroll enough pixels to cover an 'enlarged' pixel.

The markers are not inside the scroll view because they would be scaled while zooming. They are on an entirely different layer.

@incanus
Copy link
Contributor

incanus commented Jan 9, 2013

I am also resetting the zoom level back to 1 and also not drawing a bitmap, but rather using sublayers.

@specialunderwear
Copy link

Awesome, then in any case I'm positive the problem will be fixed. Not sure if having layers will change anything since cglayers are rendered to the pixel buffer as a bitmap in the end, at which point you can still do transformations on them.

So most likely you will be zooming and panning in the scrollview with the allready rendered layers. But yeah cglayer rendering is really fast.

Good luck!

@incanus
Copy link
Contributor

incanus commented Jan 9, 2013

Will keep at it. Thanks for the back-and-forth; will keep progress updated here.

@specialunderwear
Copy link

Hi how is it going? Any progress?

@cliffrowley
Copy link

Is there a workaround for this? Looking forward to a solution...

@incanus
Copy link
Contributor

incanus commented Jun 25, 2014

I should point out that this renderer is available now:

https://github.com/mapbox/mapbox-gl-cocoa

It's just not as full-featured yet as we're intending. Soon!

@specialunderwear
Copy link

Awesome go mapbox!

@incanus
Copy link
Contributor

incanus commented Jun 25, 2014

BTW any issue in this repo tagged with v is a nod to something that is more fundamental in the current renderer that can be solved by the new (vector) one (i.e., writing in OpenGL instead of using Core Graphics basing things on UIScrollView & CATiledLayer).

@incanus
Copy link
Contributor

incanus commented Jun 27, 2014

For some clarification on roadmap, I just added this: https://github.com/mapbox/mapbox-gl-cocoa/blob/master/FAQ.md

@mohpor
Copy link

mohpor commented Jun 27, 2014

Thanks @incanus for the FAQ, but it didn't answer one of my most important questions: What iOS versions will it support? The current repo says iOS 7+, will it be the same after release SDK 2.x?

@incanus
Copy link
Contributor

incanus commented Jun 27, 2014

@mohpor I've just updated the FAQ. GL will support iOS 7 & greater, which means that moving from the iOS SDK will leave behind iOS 5 and 6.

@mohpor
Copy link

mohpor commented Jun 27, 2014

Such a bad news :(

@incanus
Copy link
Contributor

incanus commented Jun 27, 2014

You can keep using the SDK for the older versions, but by the time GL is stable, iOS 8 will be out. There is already 90%+ upgrade to iOS 7 in less than a year after release, and iOS 8 only dropped the iPhone 4, so I expect similar numbers for upgrades this fall. While GLKit is available back to iOS 5, supporting iOS 7+ lets us focus on UI and UX testing for the modern platforms instead of a lot of code branching like in the iOS SDK to support the dual appearances.

@mohpor
Copy link

mohpor commented Jun 27, 2014

I see what you're saying, but as you sure know, Location Aware apps are fundamental applications that need to cover a larger than usual demographic...
I hope i can try and make it work under at least iOS 6.
Thanks for the effort and let me know if I could be of any help. I have tried and answered some issues here and on SO, to share some daily burden and make you free to work on 2.x..
Cheers

@incanus
Copy link
Contributor

incanus commented Jun 27, 2014

Yes, your help has been very much appreciate @mohpor and I am happy to work with you to help make GL unofficially available to earlier versions.

@mohpor
Copy link

mohpor commented Jun 27, 2014

Glad to help.

@pawel-sp
Copy link

pawel-sp commented Jul 3, 2014

Is there any working solution for shaking RMAnnotations problem ?

@incanus
Copy link
Contributor

incanus commented Jul 3, 2014

@pawel-sp No, not currently. This is a possible interim approach:

#72 (comment)

@BalestraPatrick
Copy link

I'm having the same problem with my RMAnnotations and it's really annoying. Any fix or workaround?

@dcacenabes
Copy link

in iOS8 the problem is gone.

@incanus
Copy link
Contributor

incanus commented Oct 1, 2014

I have noticed some changes to UIScrollView, including better debug logging. I'll bet they increased the precision to deal with potential larger content views for larger and denser displays.

@dcacenabes
Copy link

I just found out that the problem is only gone in the simulator. In a iphone 5 with iOS8 the problem still exists.

@incanus
Copy link
Contributor

incanus commented Oct 6, 2014

Dang.

To update everyone and summarize the above, this is a weakness of using a literal scroll view contentSize that maps to the actual pixel size of the whole planet once you get really far zoomed in. Each map zoom level is (2 ^ z) * 256 pixels on an edge, so z17 is 33,554,432 pixels, which runs into float precision problems.

This is solved in Mapbox GL by rendering in an OpenGL context on screen instead of a content view with virtual pixel size. Migration path coming soon...

@tabsong
Copy link

tabsong commented Nov 23, 2014

hi: incanus
You said:“Each map zoom level is (2 ^ z) * 256 pixels on an edge, so z17 is 33,554,432 pixels, which runs into float precision problems” , this conclusion is correct, but why we can't break through this precision problems. I encounter the same problem on our 2D Map SDK. using the same technology. UIScrollView+CATiledLayer. so our problem is the same. But now we have a Solution:

This solution has a basic precondition: using double/long double to convert geographic coordinate system to UIScrollView coordinate system.

And Then: We Just need to replenish the difference using translation transform. directly to reset center using "center" property is invalid.

// Get the coordinate of annotation.
CLLocationCoordinate2D coo = [annotationView.annotation coordinate];

// using long double to convert geographic coordinate system to UIScrollView coordinate system.
long double reX, reY;
[self convertLat:coo.latitude lon:coo.longitude to:&reX y:&reY];

reX += annotationView.centerOffset.x;
reY += annotationView.centerOffset.y;

// Set center first
annotationView.center = CGPointMake(reX, reY);

// Retrive the center.
CGPoint after = annotationView.center;

// Calculate the difference. We know the center will be cut to times of 2.
double dx = reX - after.x;
double dy = reY - after.y;

// Construct a translation transform.
CGAffineTransform translation = CGAffineTransformMakeTranslation(dx, dy);

// replenish the difference using translation transform
annotationView.transform = translation;

Yea: using the above code. The joggle is disappeared.

Good Luck!

@incanus
Copy link
Contributor

incanus commented Nov 24, 2014

Yes @tabsong this is what is described above in #72 (comment). However this is a pretty major refactoring and not just happening at one place in the map view code. I'd love to see this happen but we don't have the resources for it presently.

@tabsong
Copy link

tabsong commented Nov 26, 2014

@incanus Sounds like sadness, But i respect your choice. May be some days later. at lease there exists a non-elegant solution.

@leandersikma
Copy link

So we can conclude that this bug will stay unsolved. The solutions that are described earlier in this thread are too much work to make it reasonable and the Mapbox team is focussing on the MapboxGL migration. @incanus, you're saying that this bug doesn't occur in MapboxGL, right?

Unfortunately, according to the documentation MapboxGL isn't production ready and misses some features such as offline maps and annotation clustering. So, it's either using the standard Mapbox with dancing markers or use MapboxGL and hope that things as offline maps are ready in the upcoming months. Am I right at all of this?

@florianbuerger What did you decide to do to built your indoor map app?

@incanus
Copy link
Contributor

incanus commented Apr 8, 2015

@incanus, you're saying that this bug doesn't occur in MapboxGL, right?

Correct. This bug is inherent to using UIScrollView for maps and having precision problems with its API at high zoom levels because the content view is so large. Mapbox GL doesn't scroll, but actually redraws individual frames with OpenGL in response to zoom, pan, and rotation changes.

hope that things as offline maps are ready in the upcoming months

Yes. Plans for GL include offline maps and most likely clustering.

@leandersikma
Copy link

Okay, thanks.

The FAQ on MapboxGL says "The library is open source right now, but an official, production-recommended release will come later in 2015.". Does this mean that there is a big possibility that offline map support will be implemented before Q3 2015? Or is that just too optimistic?

@incanus
Copy link
Contributor

incanus commented Apr 8, 2015

I think Q3 2015 is a pretty fair estimate. We are considering offline use and programmatic runtime style API in GL to be flagship features, but post-1.0, and are looking at a 1.0 by midyear at latest, I'd say.

@Svantulden
Copy link

I'm beginning to suspect this issue is because of 32/64bit architecture. If the problem is apparent on iPhone 4 and 5, but not on 5S or 6 regardless of iOS version, it could be that.

@braandl
Copy link

braandl commented Aug 7, 2015

@Svantulden Yes, it is exactly that way.
The CGFloat in the Core Graphics on 64Bit Systems (e.g. iPhone6) is internally a double value, but on older 32 Bit devices it is a float (due to performance reasons).
The Float is not precise enough to allow this kind of behavior that the ios-sdk uses, but the double value are...

@incanus
Copy link
Contributor

incanus commented Aug 11, 2015

Just a note that this problem can be circumvented with the rapidly-maturing Mapbox Mobile OpenGL-based renderer, which can also do raster tiles.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests