RxJava - how to use methods from type referenced by Flowable? - rx-java2

I have two Flowables, which I manipulate by zipping and filtering like this:
Flowable<Position> position1 = obj1.getPosition(); // position in 3D enviroment
Flowable<Position> position2 = obj2.getPosition();
position1.zipWith(position2, (pos1, pos2) ->
getDistance(pos1,pos2) //method returning distance between positions
).filter(distance->distance<=5).subscribe();
Now I want to use methods in class Position, when filtered item got emitted like this:
position1.zipWith(position2, (pos1, pos2) ->
getDistance(pos1,pos2) //method returning distance between positions
).filter(distance->distance<=5).subscribe(pos1.getX()-pos2.getX());
How to do that?

The simplest way to solve that is creating wrapper class like this one
class Line {
Position first;
Position second;
Double distance;
}
and transform your Rx chain using it
position1
.zipWith(position2, (pos1, pos2) -> {
double distance = getDistance(pos1,pos2);
return Line(pos1, pos2, distance);
})
.filter(line -> line.distance <= 5)
.subscribe(line.first.getX()-line.second.getX())

Related

Why did Xcode warn me about making this a constant, and why does it still change?

Within my updateBlob function, Xcode warned me that pos is unchanged and should be changed to a let constant, even though I can see that it's being changed, and running the program does indeed change the position values. This all seemed to happen when I updated the BlobPos class with a defer keyword to update the x/y coordinates when it is sent the radius value. Although I could avoid using defer, why does the compiler warn me of making pos a constant, and the program is still able to change what should presumably be a constant?
class BlobPos
{
var x:CGFloat = 0
var y:CGFloat = 0
public init(radius:CGFloat) {
defer {
x = radius + 5
y = radius + 5
}
}
}
class Blob
{
var radius: CGFloat
var pos: BlobPos
init
(
radius: CGFloat,
pos: BlobPos,
)
{
self.radius = radius
self.pos = pos
}
}
func makeBlob() -> Blob
{
let radius = 8
let pos = BlobPos(radius:radius)
return Blob(radius: radius, pos: pos)
}
func updateBlob(blob:Blob)
{
let radius = blob.radius
let pos = blob.pos // compiler warning wanting me to turn this into a let constant instead of var
pos.x += 6
pos.y += 2
blob.pos = pos // strangely, new position is set
}
That is because BlobPos is a class and changing a class's properties doesn't change its location in memory, which is how classes are passed around (by reference to their location in memory). If BlobPos were a structure, then you would have to declare it a variable because structures are passed around by their values (not references to their locations in memory).

Position object in front of camera in RealityKit

I want to position an object in front of the camera, without changing its parent. The object should be in the center of the screen, at specified distance distanceFromCamera.
The object is stored as cursorEntity and is a child of sceneEntity.
A reference to the ARView is stored as arView and the position of the cursorEntity gets updated in the function updateCursorPosition
First, add forward in an extension to float4x4 that gives the forward-facing directional vector of a transform matrix.
extension float4x4 {
var forward: SIMD3<Float> {
normalize(SIMD3<Float>(-columns.2.x, -columns.2.y, -columns.2.z))
}
}
Then, implement the following 4 steps:
func updateCursorPosition() {
let cameraTransform: Transform = arView.cameraTransform
// 1. Calculate the local camera position, relative to the sceneEntity
let localCameraPosition: SIMD3<Float> = sceneEntity.convert(position: cameraTransform.translation, from: nil)
// 2. Get the forward-facing directional vector of the camera using the extension described above
let cameraForwardVector: SIMD3<Float> = cameraTransform.matrix.forward
// 3. Calculate the final local position of the cursor using distanceFromCamera
let finalPosition: SIMD3<Float> = localCameraPosition + cameraForwardVector * distanceFromCamera
// 4. Apply the translation
cursorEntity.transform.translation = finalPosition
}

Efficiently wrapping a double

I have a number of geometric functions that only accept angles in the range 0° to 360°. If the angle is outside that range then the angle is invalid (i.e. converting 365° to 5° is not an option) and there's no point in calling the functions. To this end I've created the following class:
struct PositiveAngle {
public let value: Double
init?(value: Double) {
guard 0.0 <= value && value <= 360.0 else {
return nil
}
self.value = value
}
}
To be used as follows:
let angle = PositiveAngle(value: 30.0)
print(angle.value)
func foo(angle: PositiveAngle) -> PositiveAngle {
...
}
This works but it feels "clunky" because I have extract the value of the angle from the struct whenever I need to use it. Given that all I am after is a Double that has a restricted range, is there a more efficient way to achieve this?
If you don't want to access .value in every function, you will have to add helper functions by yourself.
For example, to define sin:
func sin(_ angle: PositiveAngle) -> Double {
return sin(angle.value * Double.pi / 180)
}
Now you will be able to call sin with your PositiveAngle as an argument directly.
You can do the same for operators, e.g. +, - etc.
You could use a struct with a static function
struct AngleChecker {
static func validate(_ value : Double) -> Double? {
return (0.0...360.0).contains(value) ? value : nil
}
}
let x = AngleChecker.validate(12.0) // --> 12.0
let y = AngleChecker.validate(362.0) // --> nil
You don't want to do modulus, for reasons that aren't entirely clear to me, but I have done a lot of angle maths over the years and have always used wrap-around. In Swift,
extension Double {
var positiveAngleInDegrees: Double {
var x = self
while x < 0 { x += 360 }
while x >= 360 { x -= 360 }
return x
}
}
let y = 722.positiveAngleInDegrees // 2
In mathematical terms 722º is entirely equivalent to 2º.

Swift Enumerate out of Range

I'm working on making a tile-based adventure game and I'm trying to generate tile maps. I put together some code that removes inland tiles from the list of possible new tile locations. I have a method that detects if a tile is coastal.
for (index, tile) in landTiles.enumerate() {
let coastal = isCoastal(tile.y, x: tile.x)
if coastal {
coastTiles.append(tile)
} else {
print(landTiles.count)
print(index)
landTiles.removeAtIndex(index)
}
}
When I run this code I'm getting an error: index out of range message. I believe this is because the indexes are getting confused when I delete an item from landTiles. How could I fix this?
You are removing elements from an array while you enumerate it.
And this is an anti-pattern.
What should you do instead?
The Tile class
First of all, the Tile class should have a isCoastal computed property. Something like this
class Tile {
let x: Int
let y: Int
var isCoastal: Bool { /* your logic goes here */ }
init(x:Int, y:Int) {
self.x = x
self.y = y
}
}
Filtering
Now given an array of Tile(s)
var landTiles: [Tile] = ...
you can extract the ones having isCoastal true
let coastTiles = landTiles.filter { $0.isCoastal }
and overwrite the original array with the ones having isCoastal false.
landTiles = landTiles.filter { !$0.isCoastal }
That's it.

Functional programming way of doing array conversion

struct MapVector {
var distance: Double
var bearing: Double
}
func distanceAndBearing() -> [MapVector] {
var points = self.mapPoints
var currPoint:CLLocation = points.first!
points.removeAtIndex(0)
var result: [MapVector] = []
for point: CLLocation in points {
let calc = PointCalculator(initialPoint: currPoint, nextPoint: point)
let v = MapVector(distance: calc.pointDistance, bearing: calc.bearing)
result.append(v)
currPoint = point
}
return result
}
I am working in Swift on an application using map coordinates. I have a an array of CLLocations from which I would like to create an array of distances and bearings. The above code (its slightly simplified for readability, so may not be 100% correct) achieves that but I'd like to do it in a neater way. Is this something that can be done with map or filter? Still trying to get my head around the FP way of doing things.
Here is a simplified example for the same problem except the calculations:
let numbers = [3, 7, 2, 8, 3, 7, 5]
let result = numbers.isEmpty ? [] :
map(zip(numbers, numbers[1..<numbers.count])) {
(x, y) in
return (diff: x - y, mult: x * y)
}
result[0].diff // -4
result[0].mult // 21
Here I compute the differences and the multiplications of the numbers.
Note this will work only for Swift 1.2
In case you need it for earlier version, you should explore the use of Zip2.
For reference here are alternative solutions I came up with:-
func distanceAndBearing2() -> [MapVector]
{
// make the removeAtIndex(0) part safe
if (self.mapPoints.count == 0) {
return []
}
var t2 = self.mapPoints
t2.removeAtIndex(0)
let t3 = zip(self.mapPoints, t2)
return Array(t3).map({
(p1, p2) in
return PointCalculator(initialPoint: p1, nextPoint: p2).toMapVector()
})
}
This uses the new zip method from Xcode 6.3 Beta 2, and I moved the conversion to MapVector into the PointCalculator struct
func distanceAndBearing3() -> [MapVector] {
// make the shift part safe
if (self.mapPoints.count == 0) {
return []
}
var points = self.mapPoints
var currPoint = points.shift()!
return points.map {
point in
let initialPoint = currPoint
currPoint = point
return LocationPair(initialPoint: initialPoint,
nextPoint: point).toMapVector()
}
}
And this version uses the same toMapVector method on the PointCalculator struct, but uses a variable outside the map function which is updated by the map function; this feels like its not "correct"