Reverse a for loop of an array - swift

I'm try to create a func that should calculate the coordinate at 90deg and 270deg from each of the given coordinate..
and save it in an array of arrayLocationOffset
var arrayLocations : [CLLocationCoordinate2D] =
[
CLLocationCoordinate2D(latitude: 45.15055543976834, longitude: 11.656891939801518 ),
CLLocationCoordinate2D(latitude: 45.154446871287924, longitude: 11.66058789179949),
]
// simplify only 2 coordinate
I use this for loop in order to perform the action:
func createCoordinatePoly() {
let polypoint = arrayLocations.count
for i in 0..<polypoint {
let coord = arrayLocations[i]
// calc LH
let lhCoord = coord270(coord: coord)
arrayLocationOffset.append(lhCoord)
}
for i in 0..<polypoint { // shuld revers this for loop and get first the last index
let coord = arrayLocations[i]
// calc LH
let RhCoord = coord90(coord: coord)
arrayLocationOffset.append(RhCoord)
}
debugPrint("aggiunto array poly \(arrayLocationOffset.count)")
}
The arrayLocationOffset must have a specific sequence otherwise I can't properly draw a polygon in the Mapkit.
In order get the specific order on the second forLoop (where I calculate RHside) I should start to calculate from last array index back to the first...
is this possible?
thanks

As the name implies you can reverse an array just with reversed().
Your code is rather objective-c-ish. A better way to enumerate the array is fast enumeration because you actually don't need the index.
for coord in arrayLocations { ...
and
for coord in arrayLocations.reversed() { ...
However there is a still swiftier way mapping the arrays
func createCoordinatePoly() {
arrayLocationOffset.append(contentsOf: arrayLocations.map{coord270(coord: $0)})
arrayLocationOffset.append(contentsOf: arrayLocations.reversed().map{coord90(coord: $0)})
debugPrint("aggiunto array poly \(arrayLocationOffset.count)")
}

solved:
var reversIndex = polypoint-1
for _ in 0..<polypoint {
let coord = arrayLocations[reversIndex]
// calc LH
let RhCoord = coord90(coord: coord)
arrayLocationOffset.append(RhCoord)
reversIndex -= 1
}
I use a reverse index to start from the end...

Related

Returning Asynchronous function then assigning a value swift

I'm attempting to return the value of an array and then assign its value to a variable, however when doing so, it returns a blank array. I'm assuming this is due to my lack of knowledge on how to use async in swift so was hoping someone could show me how to do so for this segment of code:
func assignWeights(){
var weightedList = [GMUWeightedLatLng]()
getCoords { coords in
self.coords = coords
for coord in coords {
let lat = Double(coords.location.latitude)!
let long = Double(coords.location.longitude)!
let coordinates = GMUWeightedLatLng(coordinate: CLLocationCoordinate2DMake(lat,long), intensity: 2.0)
weightedList.append(coordinates)
}
print(weightedList) //Array prints contents
}
print(weightedList) //Empty array
heatmapLayer.weightedData = weightedList //Sets to empty array [] as this is ran before getCoords{
}

How to get a vertex position in ARKit's reconstructed mesh?

Recently, I make it about lidar scan project.
It is very difficult. And I need to manipulate vertex data.
So I tried by this code
guard let meshAnchors = arView.session.currentFrame?.anchors.compactMap { $0 as? ARMeshAnchor }
else { return }
meshAnchors.first?.geometry.vertices // I want to get vertex position
There is no position of vertex, only buffer data
How can I do that? is it change from buffer data to array?
Plz help me.
Just went through this myself so I figured I'd drop ya my solution.
First grab this extension from Apple's Documentation to get a vertex at a specific index:
extension ARMeshGeometry {
func vertex(at index: UInt32) -> SIMD3<Float> {
assert(vertices.format == MTLVertexFormat.float3, "Expected three floats (twelve bytes) per vertex.")
let vertexPointer = vertices.buffer.contents().advanced(by: vertices.offset + (vertices.stride * Int(index)))
let vertex = vertexPointer.assumingMemoryBound(to: SIMD3<Float>.self).pointee
return vertex
}
}
Then, to get the positions in ARKit world space, you can do something like this:
func getVertexWorldPositions(frame: ARFrame) {
let anchors = frame.anchors.filter { $0 is ARMeshAnchor } as! [ARMeshAnchor]
// Each mesh geometry lives in its own anchor
for anchor in anchors {
// Anchor's transform in world space
let aTrans = SCNMatrix4(anchor.transform)
let meshGeometry = anchor.geometry
let vertices: ARGeometrySource = meshGeometry.vertices
for vIndex in 0..<vertices.count {
// This will give you a vertex in local (anchor) space
let vertex = meshGeometry.vertex(at: UInt32(vIndex))
// Create a new matrix with the vertex coordinates
let vTrans = SCNMatrix4MakeTranslation(vertex[0], vertex[1], vertex[2])
// Multiply it by the anchors's transform to get it into world space
let wTrans = SCNMatrix4Mult(vTrans, aTrans)
// Use the coordinates for something!
let vPos = SCNVector3(wTrans.m41, wTrans.m42, wTrans.m43)
print(vPos)
}
}
}

how do i get an average value for scores in a table view (swift)?

I want to display an average for all values that are inputted into an Entity. Basically, one would press add on the TableView and a pop up would appear asking for a score, which would then add that “exam” to the tableview. I want to be able to add up all the scores and receive an average for them which i can then add to a label. I’ve tried following some other tutorial but it gives me an error.
https://i.stack.imgur.com/P7exB.jpg
https://i.stack.imgur.com/WWITI.jpg
The images above are for context.
var i = 0
var sum = 0
for i in 0...methodsExam.count {
let title = methodsExam[i]
let str : String = title.value(forKey: "score") as! String
sum = sum + Int(str)!
}
let avg = sum/methodsExam.count
averageScore.text = "Average: \(avg)"
Assuming methodsExam is an array of [MethodsExam] you can change the loop to
var sum = 0.0
for item in methodsExam {
if let scoreStr = item.score, let score = Double(scoreStr) {
sum += score
}
}
let average = sum / Double(methodsExam.count)
I am using Double here for more precision.
This could also be done with a high-order function
let average = methodsExam.reduce(into: 0.0) {
if let scoreStr = $1.score, let score = Double(scoreStr) { $0 += score }
} / Double(methodsExam.count)
Since we are dividing with the array count we must also check that the array isn't empty to avoid division by 0, so we can put the code into a function and do this
func calculateAverage(_ array: [MethodsExam]) -> Double {
guard !array.isEmpty else { return 0.0 }
return array.reduce(into: 0.0) {
if let scoreStr = $1.score, let score = Double(scoreStr) { $0 += score }
} / Double(array.count)
}
One caveat, I assumed that score can be nil because of MethodsExam being an NSManagedObject and not because it will hold nil values. If it indeed can hold nil values then you need to consider what to calculate the average on, all values in the array or only non-nil values.

Getting stuck with repeat statement

I am trying to delete all old coordinates from an array from the condition that the coordinates are too far away from my current location. However the repeat statement gets stuck on repeat, deleting all the coordinates.
var locationArray = [Double]()
var distArray = [CLLocationDistance]()
let maxDis: CLLocationDistance = CLLocationDistance(exactly: 2000)!
let LAT = Double(location.coordinate.latitude)
let LONG = Double(location.coordinate.longitude)
repeat{
locationArray.insert(contentsOf: [LAT, LONG], at: 0)
} while locationArray.count <= 4
let oldCo = CLLocation(latitude: LAT, longitude: LONG)
let newlat = locationArray[2]
let newlong = locationArray[3]
let newCo = CLLocation(latitude: newlat, longitude: newlong)
let dist = newCo.distance(from: oldCo)
distArray.append(dist)
let distArraySum = (distArray.reduce(0) { $0 + $1 })
print(distArraySum)
repeat{
if distArraySum >= maxDis {
locationArray.remove(at: locationArray.count-2)
locationArray.remove(at: locationArray.count-1)
distArray.remove(at: 0)
print("deleted Coordinates")
}
} while distArraySum >= maxDis
The app terminates because I am getting stuck on my repeat statement, and every element in the distArray gets removed until there are no more elements. So when it repeats again and I try to remove an element from an empty array, I get a fatal error.
Once you calculate disArraySum you never recalculate it within the repeat loop. The result of distArraySum >= maxDis will never change and so your loop will either always execute or never execute, but it will never dynamically change state.
Additionally, you might want to consider changing locationArray to an array of tuples; it looks like you're interleaving lat and lon, it would be easier conceptually e.g.:
var locationArray:[(lat: Double, lon: Double)] = []
This will let you avoid having to do
locationArray.remove(at: locationArray.count-2)
locationArray.remove(at: locationArray.count-1)
And while we're at it, if I can make a suggestion to use for each instead, then the final loop might look like the following untested code:
for (i, coordinates) in locationArray.enumerate().reverse() {
if (some condition using coordinates.lat and coordinates.lon) {
locationArray.removeAtIndex(i)
}
}

Swift REALM - sort by distance, filter and store only unique value

Hi I am making an app that show me interesting places. Its showing places in radius. I am using REALM to store values.
However realm don't know how to make Unique values. I am using this for Unique rows.
let result:[String] = realm.objects(E21).sorted("name").uniqueValue("Id_prov", type: String.self)
This for finding things in region around me
var datasourceE21Distance:Results<E21> = realm.findInRegion(E21.self, region: curentRegion).filter(tempRequest)
But i don't know how to combine these things to one and then sort it from closes one to me to the most far.
I will be glad for any help here.
EDIT i am using these two extensions found:
func findInRegion<T: Object>(type: T.Type, region: MKCoordinateRegion, latitudeKey: String = "lat", longitudeKey: String = "lng") -> Results<T> {
// Query
return self
.objects(type)
.filterGeoBox(region.geoBox, latitudeKey: latitudeKey, longitudeKey: longitudeKey)
}
func uniqueValue<U : Equatable>(paramKey: String, type: U.Type)->[U]{
var uniqueValues : [U] = [U]()
for obj in self {
if let val = obj.valueForKeyPath(paramKey) {
if (!uniqueValues.contains(val as! U)) {
uniqueValues.append(val as! U)
}
}
}
return uniqueValues
}
RealmGeoQueries, the library you're using for filtering your entities by a bounding box, supports sorting objects by distance via sortByDistance. This returns an array as this operation has to be done in memory with cached distances.
You would need to make sure that you're uniqueValue method is defined in an extension on Array.
I came up with something like this. But it can't filter right away :-/
let currentLocation = CLLocationCoordinate2D(latitude: currentLat!, longitude: currentLng!)
sortedObjectsByDistance = realm.findNearby(E21.self, origin: currentLocation, radius: 50000.0, sortAscending: true, latitudeKey: "lat", longitudeKey: "lng")
var seenIdProv:[String:Bool] = [:]
sortedObjectsByDistance = sortedObjectsByDistance.filter {
seenIdProv.updateValue(false, forKey: $0.Id_prov) ?? true
}