MKTileOverlay, tiles at 180.0 / -180.0 not drawn consistenly - swift

I used MKTileOverlay class to cover the map by self generated tile images.
All works good, except the tiles on the border at Longitude 180 or -180 degree. At this line, tiles are drawn only sometimes... can anybody give me a hint to solve that?
you can see the effect on this screenshot
This particular area of the map should be covered completely by this "default" tiles. The tile images itself should be OK, as they are displayed on the other tiles.
I use this loadTile(at: ... ) function to provide the generated tile images. The print statements shows that this function is called for all tiles and that the result function gets a valid image. It's just that the tiles are not drawn .. and I use the standard MKTileOverlayRenderer..
override func loadTile(at path: MKTileOverlayPath, result: #escaping (_ data: Data?, _ error: Error?) -> Void) {
let x: Int = path.x
let y: Int = path.y
let zoomLevel : Int = path.z
// calculate the x for the tile at longitude 180 degree
let xMax = (1 << zoomLevel) - 1
if (x == 0) || (x == xMax) {
print("\(zoomLevel)/\(x)/\(y) requested")
}
// local variable to hold the image of the tile
var localUIImage: UIImage = tileImageForDefaultImage
// lots of stuff to generate the tile image
// check if we have a valid image
if let resultImage = localUIImage.pngData() {
if (x == 0) || (x == xMax) {
print("resultImage: \(resultImage.debugDescription)")
}
result(resultImage, nil )
} else {
let noResultImage = tileImageForDefaultImage.pngData()
if (x == 0) || (x == xMax) {
print("noResultImage: \(noResultImage.debugDescription)")
}
result(noResultImage, nil )
}
}
.. any hint is welcomed ;-)

In short: Apple confirmed that this is a bug in IOS MapKit. At least IOS versions 11 and 12 are affected. There is no known work around so far.
Long version: I spend a DTS ticket for this and got in contact with a really good Apple engineer. After some work together, he could easily reproduce the issue. He asked me to file a bug report (49270907). By this he was able to talk to the MapKit team and they confirmed the bug.

Related

Why is my lineString not converting to mapShape in geoSwift - (only happens with one specific search), could be external library bug?

Im using the GEOSwift Library: https://github.com/GEOSwift/GEOSwift
My best guess is that if you look at the string image linked, it looks as if its not a proper circle, so maybe it is a bug in the library? But i am not at all sure about this!
Im having an issue only when i enter one specific linestring.
My app takes an array of route coordinates, converts them into WKT String (representing a line). It then Creates a buffer around this line, then converts this into a mapShape.
It runs fine, until i search one specific route.
It fails here:
func bufferPolyline(routeCoords: [CLLocationCoordinate2D], completion: #escaping (_ bufferCoordsArray: [LatLng]) -> ()) {
var wktString = ""
var i = 0
while i < routeCoords.count {
let lat = routeCoords[i].latitude
let lng = routeCoords[i].longitude
if i == routeCoords.count-1 {
let wktLast = " \(lng) \(lat)"
wktString += "\(wktLast)"
i += 1
}
if i >= 1 && i <= routeCoords.count-2 {
let wktMid = " \(lng) \(lat),"
wktString += "\(wktMid)"
i += 1
}
if i == 0 {
let wktFirst = "\(lng) \(lat),"
wktString += "\(wktFirst)"
i += 1
}
}
let linestring = Geometry.create("LINESTRING(\(wktString))")!
let string = linestring.buffer(width: 0.05)!
guard let shapeLine = string.mapShape() as? MKPolygon else {
preconditionFailure() // FAILURE HAPPENS HERE.
}
}
Here are links to images to see how it looks:
LineString - https://imgur.com/a/7OLPZkM
String - https://imgur.com/a/KJRfpRX
the linestring, and string values are still coming through even when shapeLine doesnt initialise so im struggling to see where im going wrong. They also seem to be formatted the same way.
I tried to google for a WKT String validator, but didnt find one, but i assume it should be ok, as i return multiple other searches with no issues. (i.e. the shapeLine returns a value)
My question is: does this look like a problem in my code, or a possible bug of the library? (i have little faith in my code!)

Coreplot CPTXYGraph plot not displaying correctly

I am using the latest version of Core Plot within a Swift program. The graph plots without a problem and shows the following
If you look at the plot the lower portion of the gradient fill for the plot does not match the xAxis which is the behaviour that I expect. instead it starts part way up the yAxis.
I have not experienced this behaviour before and am not sure where to hunt for the bug in my code. I haven't been able to find a relevant entry elsewhere within stackOverflow or elsewhere on the net for that matter.
I have tested the plotspace variables and they are on the money, min/max for the Y axis is as expected and the X/Y coords through the delegate functions shown below [number() and numberOfRecords()] are as expected. I am not sure what within core plot will be driving this behaviour.
If anyone is able to suggest other areas to examine for the error that would be greatly appreciated.
Rather than post all of the code initially, if someone can suggest an area to explore I will add that element of the code in to the question to help with the diagnosis. I have initially only included the code for the section of the app that defines the scatter line plot [configureLineGraph()] below the delegate functions below.
// Delegate functions for Core Plot
func numberOfRecords(for plot: CPTPlot) -> UInt {
numberOfRecordsToBeDisplayedOnGraph = UInt(arrayOfCommanderProgress.count)
return numberOfRecordsToBeDisplayedOnGraph // this needs to represent the number of records to be displayed on the graph
}
func number(for plot: CPTPlot, field fieldEnum: UInt, record idx: UInt) -> Any? {
let index = Int(numberOfRecordsToBeDisplayedOnGraph - idx) - 1
switch CPTScatterPlotField(rawValue: Int(fieldEnum))! {
case .X:
let xCoord = (arrayOfCommanderProgress[index].timeStamp.convertDateStringToDateObject()).timeIntervalSinceReferenceDate
return xCoord
case .Y:
var yCoord = Double()
if fieldEnum == 1 {
switch graphToDisplay {
case graphCombat:
yCoord = (Double(self.arrayOfCommanderProgress[index].combat)) + (100.0 * (Double(arrayOfRankProgress[index].combat)))
case graphTrade:
yCoord = (Double(self.arrayOfCommanderProgress[index].trade)) + (100.0 * (Double(arrayOfRankProgress[index].trade)))
case graphExploration:
yCoord = (Double(self.arrayOfCommanderProgress[index].explore)) + (100.0 * (Double(arrayOfRankProgress[index].explore)))
case graphFederation:
yCoord = (Double(self.arrayOfCommanderProgress[index].federation)) + (100.0 * (Double(arrayOfRankProgress[index].federation)))
case graphEmpire:
yCoord = (Double(self.arrayOfCommanderProgress[index].empire)) + (100.0 * (Double(arrayOfRankProgress[index].empire)))
case graphCQC:
yCoord = (Double(self.arrayOfCommanderProgress[index].cQC)) + (100.0 * (Double(arrayOfRankProgress[index].cQC)))
default:
break
}
}
return yCoord
}
}
// Funtions to set up the graphView and plots
func configureLineGraph() {
// Plotline variables for scatterplot
let plotLineTotal = CPTScatterPlot()
let areaGradient:CPTGradient = CPTGradient(beginning: CPTColor.clear(), ending: CPTColor(componentRed: 150/255.0, green: 180/255.0, blue: 200/255.0, alpha: 0.9))
areaGradient.angle = 90.0
let areaGradientFill:CPTFill = CPTFill(gradient: areaGradient)
// Set up plot lines for each type of total to be graphed
plotLineTotal.areaFill = areaGradientFill
// set up plotline characteristics
let plotLineType = CPTMutableLineStyle()
plotLineType.lineColor = CPTColor.darkGray()
// establish a reference to the graph custom view
guard let graph = graphView.hostedGraph else { return }
// Add additional plotlines to the plots Array if needed
let plots = [plotLineTotal]
for plot in plots {
plot.dataSource = self
plot.delegate = self
plot.areaBaseValue = CPTDecimalFromInteger(0) as NSNumber
plot.dataLineStyle = plotLineType
graph.add(plot, to: graph.defaultPlotSpace)
}
graph.reloadData()
}

Very slow minesweeper recursive algorithm in Swift

I'm working with Swift 3 and Xcode.
I'm creating an iOS game that is basically a Minesweeper, but there are no squares but hexagons, so each hexagon can have up to 6 mines in their surrounding.
I created a recursive algorithm, so that when the player touches an hexagon, if it's not a bomb, then it call a recursive function called "reveal" which :
- if one ore more mine in the surrounding and the touched hexagon is still hidden (by hidden I mean we don't know if it's a mine or not), reveal the hexagon & set the number of surrounding mine's label, and stop the function
- if no mine in the surrounding, for each nearby hexagon that is hidden, call the reveal function.
So here's what my code looks like :
class Hexagon: SKShapeNode
{
var mine: Bool
var hide: Bool
var proximityMines: Int
init(mine: Bool = false, proximityMines: Int = 0, hide: Bool = true)
{
self.mine = mine // if it's a mine
self.proximityMines = proximityMines // number of surrounding mines (that I calculated using a function after I generated the level)
self.hide = hide // if the hexagon is still hidden
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
func reveal(hexagon: Hexagon)
{
if hexagon.proximityMines == 0 && hexagon.hide == true // if there are no mines in the surrounding
{
hexagon.hide = false // we update the value of this hexagon
setNumberLabel(hexagon: hexagon) // we set the .proximityMines number as a label (here 0)
for proxyHexagon in proximityHexagons(hexagon: hexagon) // for each surrounding hexagon ...
{
if proxyHexagon.hide == true // ... that is still hidden
{
reveal(hexagon: proxyHexagon) // we call this function again
}
}
}
else if hexagon.proximityMines != 0 && hexagon.hide == true // else if there are mines in the surrounding
{
hexagon.hide = false // update
setNumberLabel(hexagon: hexagon) // set label
}
}
the proximityHexagons(hexagon: Hexagon) function returns an array containing all surrounding hexagons of a given hexagon.
So I really checked my algorithm again and again, and I really think it's the good one.
But the fact is that when I create a level with 0 or a really low amount of mine, and I click on an hexagon, it takes something like 2 seconds for the recursive function to update all the empty hexagons.
My map contains more or less 260 hexagons, and I debugged the number of calls of reveal() and it's about the same amount.
So why is it taking so much time ? I don't think the iPhone 6 can't handle this amount of operations ! I tried it on my iPhone, not an emulator.
Do you have any idea ?
Ok I've been thinking about this because it sounds like a fun problem. I didn't look up any minesweeper solvers, so I might be way out in left field, but here is how I would approach your problem.
First you have to give every mine an index, and you need to know the pattern of that index such that you can do a little math to get the surrounding indices of every mine. If the rows have identical numbers, and the numbering is sequential across rows, then the surrounding indices are:
[index - 1, index + 1,
index - rowCount, index - rowCount - 1,
index + rowCount, index + rowCount + 1]
Then I would make a class that holds a set of all the safe spots on the map that you had when you built the puzzle. I'll call it SafetyManager.
class SafetyManager {
var safeSpots: Set<Int> = all your safe spots
func indices(surrounding index: Int) -> Set<Int> {
return [index - 1, index + 1,
index - rowCount, index - rowCount - 1,
index + rowCount, index + rowCount + 1]
}
func safePlaces(around hexagon: Int) -> Set<Int> {
let allIndices = indices(surrounding: hexagon)
let safe = allIndices.intersection(safeSpots)
safeSpots.subtract(safe)
return safe
}
}
It's got two important functions, one calculates the surrounding indices, the second filters the safe spots. I'm using sets so we can quickly determine the intersection between the safe spots and the surrounding spots.
Next we need a class that would be instantiated when a move is made so we can do the recursion. Lets call it CheckManager.
class CheckManager {
var checked : [Int]
var unchecked : Set<Int>
init(firstHex: Hexagon, surroundingSafeSpots: Set<Int>) {
checked = [firstHex.index]
unchecked = surroundingSafeSpots
}
func nextUnchecked() -> Int? {
guard !unchecked.isEmpty else { return nil }
let next = unchecked.removeFirst()
checked += [next]
return next
}
func pleaseTake(these indices: Set<Int>) {
unchecked.formUnion(indices)
}
}
You initialize it with your first hexagon, or hex index, and the surrounding safespots that the safety manager would give you, if you get no safe spots from the SafetyManager, no need to instantiate.
It keeps a set of checked spots and unchecked spots. Two important functions, the second you use to give it newly acquired safe spots from the safety manager to be added to the unchecked list. The other returns an optional Int? of the next safe spot to check the surroundings of.
Then to do the recursion, something like this..
func check(spot: Hexagon) {
let safe = safetyMan.safePlaces(around: spot.index)
guard safe.count > 0 else { .. }
let checkMan = CheckManager(firstHex: spot, surroundingSafeSpots: safe)
while let i = checkMan.nextUnchecked() {
let safeSpots = safetyMan.safePlaces(around: i)
checkMan.pleaseTake(these: safeSpots)
} // goes until unchecked is empty
for spot in checkMan.checked {
// get the hex and reveal
}
}
You could keep a dictionary of [Int: Hexagon] to quickly grab the hex for a given index. I haven't tested this so I'm not sure if it works well, or at all or has some improper syntax. It would also probably be a lot faster to use multithreading. Fun problem. Good luck.
Okay, I managed to solve my problem.
The problem was the proximityHexagons function that was taking a lot of time. In fact, each time I called this function, he made 6 complex calculations and added the surrounding hexagons in an array, so it was taking a lot of time.
Here's what it looked like :
func proximityHexagons(hexagon: Hexagon) -> Array<Hexagon>
{
var array = [Hexagon]()
var nodeArray = [[Hexagon]]()
nodeArray.append(nodes(at: CGPoint(x: hexagon.position.x, y: hexagon.position.y + hexagon.height)).filter({$0 is Hexagon}) as! [Hexagon])
nodeArray.append(nodes(at: CGPoint(x: hexagon.position.x + hexagon.width * 3/4, y: hexagon.position.y + hexagon.height / 2)).filter({$0 is Hexagon}) as! [Hexagon])
nodeArray.append(nodes(at: CGPoint(x: hexagon.position.x + hexagon.width * 3/4, y: hexagon.position.y - hexagon.height / 2)).filter({$0 is Hexagon}) as! [Hexagon])
nodeArray.append(nodes(at: CGPoint(x: hexagon.position.x, y: hexagon.position.y - hexagon.height)).filter({$0 is Hexagon}) as! [Hexagon])
nodeArray.append(nodes(at: CGPoint(x: hexagon.position.x - hexagon.width * 3/4, y: hexagon.position.y - hexagon.height / 2)).filter({$0 is Hexagon}) as! [Hexagon])
nodeArray.append(nodes(at: CGPoint(x: hexagon.position.x - hexagon.width * 3/4, y: hexagon.position.y + hexagon.height / 2)).filter({$0 is Hexagon}) as! [Hexagon])
// first, for each 6 directions, I'm adding in an array every nodes that are Hexagon, and then adding all of theses arrays in another bigger one
for node in nodeArray // for each hexagon array in the big array
{
if node.count != 0 // if there is an hexagon
{
array.append(node.first!) // we set the hexagon in the final array
}
}
return array // we return the array containing all surrounding hexagons
}
I prefer checking the surrounding hexagons with the nodes(at: Point) function because my levels aren't always regular maps, they can have a weird positioning and twiz_'s func indices(surrounding index: Int) function could not work.
So I kept my function, but I call it once at the beginning of the level and store in a new variable in my hexagon class all the surrounding hexagons of each hexagon:
class Hexagon: SKShapeNode
{
var mine: Bool
var hide: Bool
var proximityMines: Int
var proxyHexagons: [Hexagon] // here
init(mine: Bool = false, proximityMines: Int = 0, hide: Bool = true, proxyHexagons: [Hexagon] =
[Hexagon]())
{
self.mine = mine
self.proximityMines = proximityMines
self.hide = hide
self.proxyHexagons = proxyHexagons
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And then, in the reveal function, instead of calling the proximityHexagons function, I use the .proxyHexagons array of the hexagon, like this :
func reveal(hexagon: Hexagon)
{
if hexagon.proximityMines == 0 && hexagon.hide == true
{
hexagon.hide = false
setNumberLabel(hexagon: hexagon)
for proxyHexagon in hexagon.proxyHexagons // here
{
if proxyHexagon.hide == true
{
reveal(hexagon: proxyHexagon)
}
}
}
else if hexagon.proximityMines != 0 && hexagon.hide == true
{
hexagon.hide = false
setNumberLabel(hexagon: hexagon)
}
}
And now my function is way faster, I manage to reveal all 260 hexagons in 0.001 secs instead of the old 2.81 secs.

how to detect motion of iPhone 6 device? (determine whether iPhone device moved or not -smallest possible motion on x,y,z- )

I'm working on a task to determine when the iPhone 6 is moving (smallest possible move not even a shake!) at any direction (x,y or Z) .
what is the best way to achieve that?
I used this code and found it useful, it contains four functions :
- Start motion manager
- Stop motion manager
- Update motion manager
- magnitudeFromAttitude
import CoreMotion
let motionManager: CMMotionManager = CMMotionManager()
var initialAttitude : CMAttitude!
//start motion manager
func StartMotionManager () {
if !motionManager.deviceMotionActive {
motionManager.deviceMotionUpdateInterval = 1
motionManager.startDeviceMotionUpdates()
}
}
//stop motion manager
func stopMotionManager ()
{
if motionManager.deviceMotionActive
{
motionManager.stopDeviceMotionUpdates()
}
}
//update motion manager
func updateMotionManager (var x : UIViewController)
{
if motionManager.deviceMotionAvailable {
//sleep(2)
initialAttitude = motionManager.deviceMotion.attitude
motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler:{
[weak x] (data: CMDeviceMotion!, error: NSError!) in
data.attitude.multiplyByInverseOfAttitude(initialAttitude)
// calculate magnitude of the change from our initial attitude
let magnitude = magnitudeFromAttitude(data.attitude) ?? 0
let initMagnitude = magnitudeFromAttitude(initialAttitude) ?? 0
if magnitude > 0.1 // threshold
{
// Device has moved !
// put the code which should fire upon device moving write here
initialAttitude = motionManager.deviceMotion.attitude
}
})
println(motionManager.deviceMotionActive) // print false
}
}
// get magnitude of vector via Pythagorean theorem
func magnitudeFromAttitude(attitude: CMAttitude) -> Double {
return sqrt(pow(attitude.roll, 2) + pow(attitude.yaw, 2) + pow(attitude.pitch, 2))
}

Use of unresolved identifier 'orientatiorawValue'

Swift keeps giving me the error typed above. This is the code.
static func rotate(orientation:Orientation, clockwise: Bool) -> Orientation {
var rotated = orientatiorawValue() + (clockwise ? 1 : -1)
if rotated > Orientation.TwoSeventy.toRaw() {
rotated = Orientation.Zero.toRaw()
} else if rotated < 0 {
rotated = Orientation.TwoSeventy.toRaw()
}
return Orientation.fromRaw(rotated)!
}
Please be very specific. Thanks in advance :).
It looks like you got halfway transitioned from Swift 1.0 to 1.1 syntax. Wherever you have .toRaw() you'll need to switch to .rawValue, and then fix this line, too:
var rotated = orientation.rawValue + (clockwise ? 1 : -1)
Lastly, your return will need to be:
return Orientation(rawValue: rotated)!