How to populate an SKShapeNode uniformly - swift

The code I am using to generate lines is so:
func populate(num: Int) {
for var i = 0; i < num; i++ {
let lines = Line(size: CGSizeMake(lineWidth, lineHeight))
let x = CGFloat(arc4random_uniform(UInt32(size.width * 20))) - size.width / 4
let y = CGFloat(arc4random_uniform(UInt32(size.height * 90))) - size.height / 100
lines.position = CGPointMake(x, y)
addChild(lines)
lines.zPosition = -1
}
It populates just fine, but they are all randomly placed (I got this code from a tutorial). I would like to know if there is a way I can uniformly generate a line every x number of points without having to manually place them. Thanks in advance.

Instead of let x = CGFloat(arc4random_uniform(UInt32(size.width * 20))) - size.width / 4
let y = CGFloat(arc4random_uniform(UInt32(size.height * 90))) - size.height / 100 you define how you want your x to be placed, for example:
let x = (i * size.width)
let y = 0
will place your lines in a single straight line along the x axis where y is 0

Related

Generate random Gaussian noise MTLTexture or MTLBuffer of size (width, height)

I am writing a real-time video filter application and for one of the algorithms I want to try out, I need to generate a random, gaussian univariate distributed buffer (or texture) based on the input source.
Coming from a Python background, the following few lines are running in about 0.15s (which is not real-time worthy but a lot faster than the Swift code I tried below):
h = 1170
w = 2532
with Timer():
noise = np.random.normal(size=w * h * 3)
plt.imshow(noise.reshape(w,h,3))
plt.show()
My Swift code try:
private func generateNoiseTextureBuffer(width: Int, height: Int) -> [Float] {
let w = Float(width)
let h = Float(height)
var noiseData = [Float](repeating: 0, count: width * height * 4)
for xi in (0 ..< width) {
for yi in (0 ..< height) {
let index = yi * width + xi
let x = Float(xi)
let y = Float(yi)
let random = GKRandomSource()
let gaussianGenerator = GKGaussianDistribution(randomSource: random, mean: 0.0, deviation: 1.0)
let randX = gaussianGenerator.nextUniform()
let randY = gaussianGenerator.nextUniform()
let scale = sqrt(2.0 * min(w, h) * (2.0 / Float.pi))
let rx = floor(max(min(x + scale * randX, w - 1.0), 0.0))
let ry = floor(max(min(y + scale * randY, h - 1.0), 0.0))
noiseData[index * 4 + 0] = rx + 0.5
noiseData[index * 4 + 1] = ry + 0.5
noiseData[index * 4 + 2] = 1
noiseData[index * 4 + 3] = 1
}
}
return noiseData
}
...
let noiseData = self.generateNoiseTextureBuffer(width: context.sourceColorTexture.width, height: context.sourceColorTexture.height)
let noiseDataSize = noiseData.count * MemoryLayout.size(ofValue: noiseData[0])
self.noiseBuffer = device.makeBuffer(bytes: noiseData, length: noiseDataSize)
How can I accomplish this fast and easily in Swift?

Convert Fisheye Video into regular Video

I have a video stream coming from a 180 degree fisheye camera. I want to do some image-processing to convert the fisheye view into a normal view.
After some research and lots of read articles I found this paper.
They describe an algorithm (and some formulas) to solve this problem.
I used tried to implement this method in a Matlab. Unfortunately it doesn't work, and I failed to make it work. The "corrected" image looks exactly like the original photograph and there's no any removal of distortion and secondly I am just receiving top left side of the image, not the complete image but changing the value of 'K' to 1.9 gives mw the whole image, but its exactly the same image.
Input image:
Result:
When the value of K is 1.15 as mentioned in the article
When the value of K is 1.9
Here is my code:
image = imread('image2.png');
[Cx, Cy, channel] = size(image);
k = 1.5;
f = (Cx * Cy)/3;
opw = fix(f * tan(asin(sin(atan((Cx/2)/f)) * k)));
oph = fix(f * tan(asin(sin(atan((Cy/2)/f)) * k)));
image_new = zeros(opw, oph,channel);
for i = 1: opw
for j = 1: oph
[theta,rho] = cart2pol(i,j);
R = f * tan(asin(sin(atan(rho/f)) * k));
r = f * tan(asin(sin(atan(R/f))/k));
X = ceil(r * cos(theta));
Y = ceil(r * sin(theta));
for k = 1: 3
image_new(i,j,k) = image(X,Y,k);
end
end
end
image_new = uint8(image_new);
warning('off', 'Images:initSize:adjustingMag');
imshow(image_new);
This is what solved my problem.
input:
strength as floating point >= 0. 0 = no change, high numbers equal stronger correction.
zoom as floating point >= 1. (1 = no change in zoom)
algorithm:
set halfWidth = imageWidth / 2
set halfHeight = imageHeight / 2
if strength = 0 then strength = 0.00001
set correctionRadius = squareroot(imageWidth ^ 2 + imageHeight ^ 2) / strength
for each pixel (x,y) in destinationImage
set newX = x - halfWidth
set newY = y - halfHeight
set distance = squareroot(newX ^ 2 + newY ^ 2)
set r = distance / correctionRadius
if r = 0 then
set theta = 1
else
set theta = arctangent(r) / r
set sourceX = halfWidth + theta * newX * zoom
set sourceY = halfHeight + theta * newY * zoom
set color of pixel (x, y) to color of source image pixel at (sourceX, sourceY)

Where a vector would intersect the screen if extended towards it's direction (swift)

I'm trying to write a function in swift, which returns a CGPoint where the extension of a vector (which is within a screen) will intersect the screen. Let's assume that the screen is 800 x 600. It's like the scheme:
The function should have the following parameters:
func calcPoint(start: CGPoint, end: CGPoint) -> CGPoint
start: CGPoint(x: x1, y: y1) - this is the beginning of the vector.
end: CGPoint(x: x1, y: y1) - this is the end point of the vector.
the return point is the one at which the vector intersects the screen (CGPoint(x: x3, y: y3) as shown at the scheme).
The values for the vector start and end are aways points within the screen (the rectangle 0, 0, 800, 600).
EDIT (for Alexander):
Is there a formula, which in the given situation will make it easy to write the function, in not the obvious way using if ... else ... and triangle vertices ratio?
To compute point E you can look at the triangles given by your setting. You have the Triangle ABC and DBE. Note that they are similar, such that we can set up following relation AB : AC = DB : DE using the intercept theorem (AB etc. stands for the line segment between A and B). In the given setting you know all points but E.
Using start and end Points from given setting:
In case start and end have the same x or y-coordinate it is only the top bottom or left right border with the same coordinate.
Using the absolute values it should work for all four corners of your rectangle. Then of course you have to consider E being out of your rectangle, again the same relation can be used AB : AC = D'B : D'E'
A pure swift solution for everyone interested in such (thanks to Ivo Ivanoff):
// Example for iOS
/// The height of the screen
let screenHeight = UIScreen.main.bounds.height
/// The width of the screen
let screenWidth = UIScreen.main.bounds.width
func calculateExitPoint(from anchor : CGPoint, to point: CGPoint) -> CGPoint {
var exitPoint : CGPoint = CGPoint()
let directionV: CGFloat = anchor.y < point.y ? 1 : -1
let directionH: CGFloat = anchor.x < point.x ? 1 : -1
let a = directionV > 0 ? screenHeight - anchor.y : anchor.y
let a1 = directionV > 0 ? point.y - anchor.y : anchor.y - point.y
let b1 = directionH > 0 ? point.x - anchor.x : anchor.x - point.x
let b = a / (a1 / b1)
let tgAlpha = b / a
let b2 = directionH > 0 ? screenWidth - point.x : point.x
let a2 = b2 / tgAlpha
exitPoint.x = anchor.x + b * directionH
exitPoint.y = point.y + a2 * directionV
if (exitPoint.x > screenWidth) {
exitPoint.x = screenWidth
} else if (exitPoint.x < 0) {
exitPoint.x = 0;
} else {
exitPoint.y = directionV > 0 ? screenHeight : 0
}
return exitPoint
}
Any kind of optimizations are welcomed ;-)
There is no single formula, because intersection depends on starting point position, line slope and rectangle size, and it may occur at any rectangle edge.
Here is approach based on parametric representation of line. Works for any slope (including horizontal and vertical). Finds what border is intersected first, calculates intersection point.
dx = end.x - start.x
dy = end.y - start.y
//parametric equations for reference:
//x = start.x + dx * t
//y = start.y + dy * t
//prerequisites: potential border positions
if dx > 0 then
bx = width
else
bx = 0
if dy > 0 then
by = height
else
by = 0
//first check for horizontal/vertical lines
if dx = 0 then
return ix = start.x, iy = by
if dy = 0 then
return iy = start.y, ix = bx
//in general case find parameters of intersection with horizontal and vertical edge
tx = (bx - start.x) / dx
ty = (by - start.y) / dy
//and get intersection for smaller parameter value
if tx <= ty then
ix = bx
iy = start.y + tx * dy
else
iy = by
ix = start.x + ty * dx
return ix, iy

Sine Wave UIBezierPath between two points

How does one create a path of a sine wave between two points?
I am able to create a path of a sine wave from an origin, but am not sure how the direction can be transformed so that the sine wave ends at a target CGPoint.
I would like to animate a SKNode along the path using SKAction.followPath
The simplest way to think about this is to transform the coordinate system, rotating by the angle between the two points, scaling by the distance between them and translating by the first point (assuming the sine starts at 0,0).
The OP has specified that he doesn't just want to draw the curve (in which case all one needs to do is apply the transform to the graphics context), but rather to use the curve in a SpriteKit SKAction.followPath call, so the transform has to be applied to the coordinates in the path, not to the context.
Here's a solution using CGPath rather than UIBezierPath, but they are equivalent, and you can get the UI version simply by let uip = UIBezierPath(cgPath: path). (I prefer CoreGraphics as they are cross-platform).
Playground code...
class MyView: UIView {
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.setFillColor(UIColor.red.cgColor)
context.fill(self.bounds)
// Calculate the transform
let p1 = CGPoint(x: 100, y: 100)
let p2 = CGPoint(x: 400, y: 400)
let dx = p2.x - p1.x
let dy = p2.y - p1.y
let d = sqrt(dx * dx + dy * dy)
let a = atan2(dy, dx)
let cosa = cos(a) // Calculate only once...
let sina = sin(a) // Ditto
// Initialise our path
let path = CGMutablePath()
path.move(to: p1)
// Plot a parametric function with 100 points
let nPoints = 100
for t in 0 ... nPoints {
// Calculate the un-transformed x,y
let tx = CGFloat(t) / CGFloat(nPoints) // 0 ... 1
let ty = 0.1 * sin(tx * 2 * CGFloat.pi ) // 0 ... 2π, arbitrary amplitude
// Apply the transform
let x = p1.x + d * (tx * cosa - ty * sina)
let y = p1.y + d * (tx * sina + ty * cosa)
// Add the transformed point to the path
path.addLine(to: CGPoint(x: x, y: y))
}
// Draw the path
context.setStrokeColor(UIColor.blue.cgColor)
context.addPath(path)
context.strokePath()
}
}
let v = MyView(frame: CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 500, height: 500)))
Not crystal clear what you want but here's one possibility assuming you want a tilted sin curve:
Assume that the start point is (0, 0) and the end point is (x, y).
Let L be the distance between the origin and your point: L = sqrt(x^2 + y^2)
Write a loop that starts at 0 and ends at L, with increment dL and running sum l (which ends up running between 0 and L). This loop will allow us to create the points on your Bezier.
Then the x coordinate of your sin graph will be:
x_P = l * cos(theta), ranging from 0 to L * cos(theta) = x
To get the y coordinate, we add a sin function with the correct period to the sloping line between the origin and your point:
y_P = l * sin(theta) + sin(2 * PI * l / L)
note that, at l = L, (x_P, y_P) = (x, y) which is as it should be.
Was this what you wanted? It is not a rotation and so will not behave when the angle theta is large.

Fastest Inverse Square Root on iPhone (Swift, not ObjectC)

Refer to
Fastest Inverse Square Root on iPhone
I need do a "Fastest Inverse Square Root" on iPhone iOS Swift, which is supposed to be faster than 1/sqrt(float).
How do I do it?
In embedded C programming, it is:
// Fast inverse square-root
// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
func invSqrt(x: Float) -> Float {
var halfx : Float = 0.5 * x
var y : Float = x
long i = *(long*)&y
i = 0x5f3759df - (i>>1)
y = *(float*)&i
y = y * (1.5 - (halfx * y * y))
return y
}
The only tricky part is how to do the forced conversions between floating
point numbers and integer types, and the easiest way is to use
memcpy():
// Fast inverse square-root
// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
func invSqrt(x: Float) -> Float {
let halfx = 0.5 * x
var y = x
var i : Int32 = 0
memcpy(&i, &y, 4)
i = 0x5f3759df - (i >> 1)
memcpy(&y, &i, 4)
y = y * (1.5 - (halfx * y * y))
return y
}
I made some performance tests on an iPhone 6s with 1.000.000 random
floating point numbers in the range 0 ... 1000, and it turned out
that invSqrt(x) is about 40% faster than 1.0/sqrt(x).
The maximal relative error was below 0.176%, confirming the bound in
the Wikipedia article.
I also made a test with vvrsqrtf from the
Accelerate framework, but this was actually slower than
calling 1.0/sqrt(x), at least when called with single floating
point numbers.
As of Swift 3, memcpy() can be replaced by the bitPattern:
method of Float and the corresponding constructor from UInt32:
func invSqrt(x: Float) -> Float {
let halfx = 0.5 * x
var i = x.bitPattern
i = 0x5f3759df - (i >> 1)
var y = Float(bitPattern: i)
y = y * (1.5 - (halfx * y * y))
return y
}