Animating sprites on top of mapview (iOS) - ios

I am developing an application which will show where trains are at any given time. It will receive gpx-data from the trains to get their location.
Is there any way to animate a sprite moving along a restricted line in a mapview? In my example, a train moving along a trainroute.
I have drawn the trainroutes as polyline in an overlay, and the train is an annotation.

I ended up making a visible overlay, then making a separate array out of the same coordinates.
To simulate the movement, the MKAnnotations uses 'setCoordinate' while iterating the array, which in fact is the same as the overlay.
This made the annotations look like they moved atop of a restricted overlay.

Related

Prevent GMSMarkers from Scaling on iOS?

I am using GMSMarkers on iOS with the Google Maps API. I have a GMSMarker with a PNG image and no matter my zoom level on the map view the GMSMarker keeps its size respective to the screen. If I zoom in it is 30 points across the screen, and if I am zoomed all the way out on the map it is still 30 points. I do NOT want this to happen, I want the GMSMarker to stay small no matter what the zoom level is. It would be preferable that I do not have to loop through all my GMSMarkers every time the camera zoom changes, as I will be eventually having 50-100 of them on the map.
Is there anyway to keep the GMSMarker small no matter the zoom level on the GMSMapView?
I am using Objective-C, but if someone can only give me help in Swift or even Java I can still make do with that.
You could use a GMSGroundOverlay to add an image to the map which scales along with the map. So instead of a fixed size in pixels like a GMSMarker, it stays a fixed size in metres.
Note that another difference is that a ground overlay also stays oriented with the map, ie if the map is rotated/tilted, the top of the image rotates to point north, instead of staying pointing to the top of the screen like a marker.

How to enforce touching within a ring shape using iOS SpriteKit?

I need to have the player moving the finger within the shaded ring:
The program should be able to detect "out of boundary" events once the finger moves outside the ring (shown in red).
Any best practices for doing this in SpriteKit, ideally in Swift? Thanks!
You could draw your shapes using CGPath, then use CGPathContainsPoint to determine if the touched locations are inside or outside the path.
You can use CGPaths like this in SpriteKit using SKShapeNode.

Interact with complex figure in iOS

I need to be able to interact with a representation of a cilinder that has many different parts in it. When the users taps over on of the small rectangles, I need to display a popover related to the specific piece (form).
The next image demonstrates a realistic 3d approach. But, I repeat, I need to solve the problem, the 3d is NOT required (would be really cool though). A representation that complies the functional needs will suffice.
The info about the parts to make the drawing comes from an API (size, position, etc)
I dont need it to be realistic really. The simplest aproximation would be to show a cilinder in a 2d representation, like a rectangle made out of interactable small rectangles.
So, as I mentioned, I think there are (as I see it) two opposite approaches: Realistic or Simplified
Is there a way to achieve a nice solution in the middle? What libraries, components, frameworks that I should look into?
My research has led me to SceneKit, but I still dont know if I will be able to interact with it. Interaction is a very important part as I need to display a popover when the user taps on any small rectangle over the cylinder.
Thanks
You don't need any special frameworks to achieve an interaction like this. This effect can be achieved with standard UIKit and UIView and a little trigonometry. You can actually draw exactly your example image using 2D math and drawing. My answer is not an exact formula but involves thinking about how the shapes are defined and break the problem down into manageable steps.
A cylinder can be defined by two offset circles representing the end pieces, connected at their radii. I will use an orthographic projection meaning the cylinder doesn't appear smaller as the depth extends into the background (but you could adapt to perspective if needed). You could draw this with CoreGraphics in a UIView drawRect.
A square slice represents an angle piece of the circle, offset by an amount smaller than the length of the cylinder, but in the same direction, as in the following diagram (sorry for imprecise drawing).
This square slice you are interested in is the area outlined in solid red, outside the radius of the first circle, and inside the radius of the imaginary second circle (which is just offset from the first circle by whatever length you want the slice).
To draw this area you simply need to draw a path of the outline of each arc and connect the endpoints.
To check if a touch is inside one of these square slices:
Check if the touch point is between angle a from the origin at a.
Check if the touch point is outside the radius of the inside circle.
Check if the touch point is inside the radius of the outside circle. (Note what this means if the circles are more than a radius apart.)
To find a point to display the popover you could average the end points on the slice or find the middle angle between the two edges and offset by half the distance.
Theoretically, doing this in Scene Kit with either SpriteKit or UIKit Popovers is ideal.
However Scene Kit (and Sprite Kit) seem to be in a state of flux wherein nobody from Apple is communicating with users about the raft of issues folks are currently having with both. From relatively stable and performant Sprite Kit in iOS 8.4 to a lot of lost performance in iOS 9 seems common. Scene Kit simply doesn't seem finished, and the documentation and community are both nearly non-existent as a result.
That being said... the theory is this:
Material IDs are what's used in traditional 3D apps to define areas of an object that have different materials. Somehow these Material IDs are called "elements" in SceneKit. I haven't been able to find much more about this.
It should be possible to detect the "element" that's underneath a touch on an object, and respond accordingly. You should even be able to change the state/nature of the material on that element to indicate it's the currently selected.
When wanting a smooth, well rounded cylinder as per your example, start with a cylinder that's made of only enough segments to describe/define the material IDs you need for your "rectangular" sections to be touched.
Later you can add a smoothing operation to the cylinder to make it round, and all the extra smoothing geometry in each quadrant of unique material ID should be responsive, regardless of how you add this extra detail to smooth the presentation of the cylinder.
Idea for the "Simplified" version:
if this representation is okey, you can use a UICollectionView.
Each cell can have a defined size thanks to
collectionView:layout:sizeForItemAtIndexPath:
Then each cell of the collection could be a small rectangle representing a
touchable part of the cylinder.
and using
collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath
To get the touch.
This will help you to display the popover at the right place:
CGRect rect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
Finally, you can choose the appropriate popover (if the app has to work on iPhone) here:
https://www.cocoacontrols.com/search?q=popover
Not perfect, but i think this is efficient!
Yes, SceneKit.
When user perform a touch event, that mean you knew the 2D coordinate on screen, so your only decision is to popover a view or not, even a 3D model is not exist.
First, we can logically split the requirement into two pieces, determine the touching segment, showing right "color" in each segment.
I think the use of 3D model is to determine which piece of data to show in your case if I don't get you wrong. In that case, the SCNView's hit test method will do most of work for you. What you should do is to perform a hit test, take out the hit node and the hit's local 3D coordinate of this node, you can then calculate which segment is hit by this touch and do the decision.
Now how to draw the surface of the cylinder would be the only left question, right? There are various ways to do, for example simply paint each image you need and programmatically and attach it to the cylinder's material or have your image files on disk and use as material for the cylinder ...
I think the problem would be basically solved.

Can a map overlay be moved?

I'm displaying several user's locations on a map simultaneously as circles of different colors.
I can do this using an annotation and then when the user's location updates use UIView:animateWithDuration: to move to their new location.
However there is a requirement that the size of the circles reflects the accuracy of the location i.e. very accurate equals a circle of size 10 meters, rough accuracy is represented as a circle of size 500 meters etc.
However there are two problems using annotations for this - the first is how to transform meters into a CGRect on the correct size to draw on the map. And the second is the annotations need to be resized if the user zooms the map.
So I was looking at using an overlay instead as that already has a radius and automatic resizing during zooming built in so it handles those two problems.
However it looks like overlays are meant to be static and their coordinate property is read only.
Is there some way I can make the overlays move as the user's location moves? (other than completely remove it and re-add it?)
[THis is for iOS 7 only]

Combining MKOverlays

I need to draw many (hundreds to thousands) of square overlays on a map. The positions and sizes of these overlays stay constant. I think that I can speed up rendering by combining these square overlays into a single overlay so drawMapRect only needs to be called once. Is this possible?
In my case, removing overlays is not an option. A way I found to drastically improve performance was to have my overlay class store an array of the square overlays. Then in my overlayView's drawMapRect method, I looped over the array to draw all the overlays. Something very similar is done in the HazardMap Apple Developer Example. See drawMapRect in HazardMapView.m
I had similar problem for MKAnnotation.
And I found following link:
http://www.fiveminutes.eu/having-fun-with-ios-map-kit-grouping-annotations/
Iterate annotation list and calculate a distance of two annotation's coordinate.
If there's nearby annotation exist, remove it from the list.
I think this approach can be applicable to MKOverlays too.

Resources