Why do I need to initialize the struct with self.init() even if I assign all of the properties? - swift

In simd_float4x4, columns is the only property, however, this won't work solely because I'm not calling self.init(). Everything would have been initialize anyway. Why is the compiler complaining? I saw something similar in this video, and it was working. Why can't I do it?
extension simd_float4x4 {
init(ProjectionFrame: CGSize) {
let Y = FOV(), FarZ = Float((Settings.VisibilityRange+1)*2), Z = FarZ / (NearZ - FarZ)
columns = (vector_float4(Y / Float(ProjectionFrame.width / ProjectionFrame.height), 0, 0, 0), vector_float4(0, Y, 0, 0), vector_float4(0, 0, Z, -1), vector_float4(0, 0, Z * NearZ, 0))
}
}
In the video I noticed this.
extension simd_float4x4 {
init(translationX x: Float, x: Float, x: Float) {
columns = (
vector_float4(x, 0, 0, 0),
vector_float4(0, x, 0, 0),
vector_float4(0, 0, x, 0),
vector_float4(0, 0, 0, 1)
)
}
}
And the compiler wasn't complaining. How come it's complaining for me?

Instead of trying to set columns from your init, you should just call self.init(_ columns:) and pass in the 4 vector_float4s as an Array rather than as a tuple.
extension simd_float4x4 {
init(ProjectionFrame: CGSize) {
let Y = FOV(), FarZ = Float((Settings.VisibilityRange+1)*2), Z = FarZ / (NearZ - FarZ)
self.init([vector_float4(Y / Float(ProjectionFrame.width / ProjectionFrame.height), 0, 0, 0), vector_float4(0, Y, 0, 0), vector_float4(0, 0, Z, -1), vector_float4(0, 0, Z * NearZ, 0)])
}
}
That video is 2 years old and hence uses an older Swift version. The code you link from that video also doesn't compile in Swift 5.
Unrelated to your question, but variable names in Swift should be lowerCamelCase, so projectionFrame is the correct naming.

Alternatively I could bridge it to C
#include <simd/simd.h>
matrix_float4x4 ProjectPerspective(const float Ratio) {
const float Y = 1/tanf(Rad(Settings.FOV+15)), FarZ = (Settings.VisibilityRange+1)*32, Z = FarZ/(NearZ-FarZ);
return (matrix_float4x4){.columns = {{Y/Ratio, 0, 0, 0}, {0, Y, 0, 0}, {0, 0, Z, -1}, {0, 0, Z*NearZ, 0}}};
}

Related

How to move PointCloud to coordinates center?

I have a PointCloud which have points with position(x, y, z) and color(r, g, b)
But points lays in big distance from coordinates canter:
Question is: what algorithm can be used to place all points to coordinates center? My guess is to create translation matrix and multiply all pointCloud points to it, but I can't determine what this matrix should contain
Just found an answer. Need to find center of mass of PointCloud with something like this:
var summX: Float = 0
var summY: Float = 0
var summZ: Float = 0
for point in points {
summX += point.x
summY += point.y
summZ += point.z
}
let middleX = summX / Float(points.count)
let middleY = summY / Float(points.count)
let middleZ = summZ / Float(points.count)
let centerOfMass = Float3(x: middleX, y: middleY, z: middleZ)
Then create translation matrix
And finally multiply all points to this matrix
let translationMatrix = float4x4(simd_float4(x: 1, y: 0, z: 0, w: -centerOfMass.x),
simd_float4(x: 0, y: 1, z: 0, w: -centerOfMass.y),
simd_float4(x: 0, y: 0, z: 1, w: -centerOfMass.z),
simd_float4(x: 0, y: 0, z: 0, w: 1))
let translatedPoints = points.map { point in
return point * translationMatrix
}

Pairwise post-hoc testing using coefTest (MATLAB)

I found this post from back in 2015 but it doesn't seem to answer the question (and if it does, I am sorry that I am missing it!). I am trying to understand how I can test for differences within a level of an interaction. For this purpose I have created a random dataset with known properties. In my mock dataset, I have a group of subjects who participate in something-or-other. They can belong to one of three Groups (ABC) at the time of test. Then, we have three factors (ABC) under which we have three levels for each (A-DEF, B-GHI, C-JKL). I arranged the data such that of the groupings, only Group C has any effect (i.e., 2) and then there is a significant interaction factor C, in that if you have level L, you get a big boost.
Thus, any analysis should hopefully detect a signficiant main effect of Group and a significant Group x Factor C interaction effect, but no other obvious effects. Within the effect of Group, it should be level C that stands out. Within the interaction, it should be level L that stands out.
My mock dataset can be found here.
To test my understanding, I generated the below script. In it, I am (very sure) I am correctly using coefTest to detect the significant main and interaction effects. Within the main effect, I am (somewhat sure) I am correctly using coefTest to perform pairwise comparisons among Groups ABC; as predicted, I find that C is different from both A and B, while A and B do not differ.
However, within the interaction effect, I would like to test for differences among levels JKL. Can this be done? If so, can someone please help me to do so?
Thank you!!!
load table.mat
mdl = fitlme(d, ...
'Value ~ Group*FactorA + Group*FactorB + Group*FactorC + (1|Subject)', ...
'DummyVarCoding', 'effects', 'FitMethod', 'REML');
disp(mdl)
%% Generate predictions for ALL data
g = unique(d.Group);
a = unique(d.FactorA);
b = unique(d.FactorB);
c = unique(d.FactorC);
cv = sortrows(combvec(1:numel(g), 1:numel(a), 1:numel(b), 1:numel(c))');
predTable = table();
predTable.Subject(1:size(cv, 1),1) = categorical({'Generic'});
predTable.Group = g(cv(:,1),1);
predTable.FactorA = a(cv(:,2),1);
predTable.FactorB = b(cv(:,3),1);
predTable.FactorC = c(cv(:,4),1);
predTable.Value = predict(mdl, predTable, 'Conditional', false);
% Trim to only Groups and then only groupxfactor C interaction
[~, ia, ~] = unique(predTable.Group);
groupTable = removevars(predTable(ia,:), ...
{'Subject', 'FactorA', 'FactorB', 'FactorC'});
groupTable.Value = splitapply(#mean, predTable.Value, ...
findgroups(predTable.Group));
[~, ia, ~] = unique(predTable.FactorC);
AxFactorCTable = removevars(predTable(ia,:), ...
{'Subject', 'Group', 'FactorA', 'FactorB'});
AxFactorCTable.Value = splitapply(#mean, ...
predTable.Value(predTable.Group == 'A'), ...
findgroups(predTable.FactorC(predTable.Group == 'A')));
BxFactorCTable = removevars(predTable(ia,:), ...
{'Subject', 'Group', 'FactorA', 'FactorB'});
BxFactorCTable.Value = splitapply(#mean, ...
predTable.Value(predTable.Group == 'B'), ...
findgroups(predTable.FactorC(predTable.Group == 'B')));
CxFactorCTable = removevars(predTable(ia,:), ...
{'Subject', 'Group', 'FactorA', 'FactorB'});
CxFactorCTable.Value = splitapply(#mean, ...
predTable.Value(predTable.Group == 'C'), ...
findgroups(predTable.FactorC(predTable.Group == 'C')));
figure('units', 'normalized', 'outerposition', [0; 0; 1; 1])
subplot(2, 3, 2)
bar(groupTable.Group, groupTable. Value)
title('Group Means')
ylim([-3, 6])
axis square
subplot(2, 3, 4)
bar(AxFactorCTable.FactorC, AxFactorCTable. Value)
title('Factor C Means for Group A')
ylim([-3, 6])
axis square
subplot(2, 3, 5)
bar(BxFactorCTable.FactorC, BxFactorCTable. Value)
title('Factor C Means for Group B')
ylim([-3, 6])
axis square
subplot(2, 3, 6)
bar(CxFactorCTable.FactorC, CxFactorCTable. Value)
title('Factor C Means for Group C')
ylim([-3, 6])
axis square
% Perform pairwise testing among the main effects for each group.
% Because Group C is not assigned to an effect, it can be tricky to do
% pairwise comparisons with it. However, following the comparison
% approach found at
% https://www.mathworks.com/help/stats/generalizedlinearmixedmodel.coeftest.html,
% we can determine what the post hoc arrangements should be:
% syms A B C
% f1 = A + B + C == 0;
% C = solve(f1, C)
% fAB = A - B
% fAC = A - C
% fBC = B - C
% The results are:
% C = -A - B
% fAB = A - B
% fAC = 2*A + B
% fBC = A + 2*B
% [Int, G_A, G_B, FA_D, FA_E, FB_G, FB_H, FC_J, FC_K, G_A:FA_D, G_B:FA_D, G_A:FA_E, G_B:FA_E, G_A:FB_G, G_B:FB_G, G_A:FB_H, G_B:FB_H, G_A:FC_J, G_B:FC_J, G_A:FC_K, G_B:FC_K]
HAB = [ 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
HAC = [ 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
HBC = [ 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pG = coefTest(mdl, [HAB; HAC; HBC]);
pAB = coefTest(mdl, HAB);
pAC = coefTest(mdl, HAC);
pBC = coefTest(mdl, HBC);
disp(['Significance of Group effect: ', num2str(pG, 3)])
disp([' * Significance of Group A vs. Group B difference: ', ...
num2str(pAB, 3)])
disp([' * Significance of Group A vs. Group C difference: ', ...
num2str(pAC, 3)])
disp([' * Significance of Group B vs. Group C difference: ', ...
num2str(pBC, 3)])
% [Int, G_A, G_B, FA_D, FA_E, FB_G, FB_H, FC_J, FC_K, G_A:FA_D, G_B:FA_D, G_A:FA_E, G_B:FA_E, G_A:FB_G, G_B:FB_G, G_A:FB_H, G_B:FB_H, G_A:FC_J, G_B:FC_J, G_A:FC_K, G_B:FC_K]
HG_FA = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]];
HG_FB = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]];
HG_FC = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]];
pG_FA = coefTest(mdl, HG_FA);
pG_FB = coefTest(mdl, HG_FB);
pG_FC = coefTest(mdl, HG_FC);
disp(' ')
disp(['Significance of Group vs. Factor A interaction: ', ...
num2str(pG_FA, 3)]);
disp(['Significance of Group vs. Factor B interaction: ', ...
num2str(pG_FB, 3)]);
disp(['Significance of Group vs. Factor C interaction: ', ...
num2str(pG_FC, 3)]);
disp(' * Here''s where I would like to test for differences among JKL within Group C')
% Uncomment to check above against MATLAB anova
% disp(' ')
% disp(anova(mdl))
Some helpful output to visualize expected outcomes

How to smooth interpolation of a float array into a bigger array?

I'm stuck with interpolation in Swift. Can anyone help me with that?
I want to interpolate the float array (say [0, 0, 100, 25, 0, 0, 0, 25, 0, 0, 0]) into another array with some given size (for example 128). I found an article (Use Linear Interpolation to Construct New Data Points) that shows, how to achieve this stuff.
There are two ways (you can see the results below, how they perform):
Linear Interpolation using vDSP_vgenp and
Smoother (but not for my purposes) Interpolation using vDSP_vlint
The problem is both techniques don't realize my expectations, which illustrated in Screenshot 3. How can I make my interpolated distribution smoother? I want to see a cube-like curve.
Initial Plot:
Linear Interpolation:
import Accelerate
let n = vDSP_Length(128)
let stride = vDSP_Stride(1)
let values: [Float] = [0, 0, 100, 25, 0, 0, 0, 25, 0, 0, 0]
let indices: [Float] = [0, 11, 23, 34, 46, 58, 69, 81, 93, 104, 116]
var result = [Float](repeating: 0, count: Int(n))
vDSP_vgenp(values, stride, indices, stride, &result, stride, n, vDSP_Length(values.count))
Smooth Interpolation:
import Accelerate
import AVFoundation
let n = vDSP_Length(1024)
let stride = vDSP_Stride(1)
let values: [Float] = [0, 0, 100, 25, 0, 0, 0, 25, 0, 0, 0]
let denominator = Float(n) / Float(values.count - 1)
let control: [Float] = (0 ... n).map {
let x = Float($0) / denominator
return floor(x) + simd_smoothstep(0, 1, simd_fract(x))
}
var result = [Float](repeating: 0, count: Int(n))
vDSP_vlint(values, control, stride, &result, stride, n, vDSP_Length(values.count))
It seems to me that the vDSP_vqint quadratic interpolation functions would solve the problem. See the discussion at https://developer.apple.com/documentation/accelerate/1449942-vdsp_vqint.

Building a Perspective Projection Matrix

my first post here but hopefully I can explain my dilemma with building a perspective projection matrix similar to the one in OpenGL. Being new to the 3D graphics space, I'm having trouble understanding what to do after multiplying my matrix after using a perspective projection multiplication. I'm attempting to create this in Flutter but it should be a moot point as I believe my conversion is off.
Here is what I have:
var center = {
'x': size.width / 2,
'y': size.height / 2
};
List points = [];
points.add(createVector(-50, -50, -50, center));
points.add(createVector(50, -50, -50, center));
points.add(createVector(50, 50, -50, center));
points.add(createVector(-50, 50, -50, center));
points.add(createVector(-50, -50, 50, center));
points.add(createVector(50, -50, 50, center));
points.add(createVector(50, 50, 50, center));
points.add(createVector(-50, 50, 50, center));
for (int i = 0; i < points.length; i++) {
var matrix = matmul(projection, points[i]);
var w = matrix[3][0];
projected.add(
Offset(
(matrix[0][0] / w),
(matrix[1][0] / w)
)
);
}
And these are the 2 custom functions I've created:
List createVector(x, y, z, center) {
return [
[center['x'] + x],
[center['y'] + y],
[z],
[0]
];
}
List matmul(a, b) {
int colsA = a[0].length;
int rowsA = a.length;
int colsB = b[0].length;
int rowsB = b.length;
if (colsA != rowsB) {
return null;
}
List result = [];
for (int j = 0; j < rowsA; j++) {
result.add([]);
for (int i = 0; i < colsB; i++) {
double sum = 0.0;
for (int n = 0; n < colsA; n++) {
sum += a[j][n] * b[n][i];
}
result[j].add(sum);
}
}
return result;
}
My projection matrix that I'm multiplying each point with is:
var aspect = size.width / size.height;
var fov = 100;
var near = 200;
var far = 300;
List projection = [
[1 / (aspect * tan(fov / 2)), 0, 0, 0],
[0, 1 / (tan(fov / 2)), 0, 0],
[0, 0, (near + far) / (near - far), (2 * near * far) / (near - far)],
[0, 0, -1, 0]
];
I believe I am using the correct projection matrix to multiply each vector point that I have. The only thing is, after I get the result from this multiplication, I'm not entirely sure what to do with the resultant vector. I've read about the perspective divide so I am dividing the x, y and z values by the 4th values but I could be incorrect.
Any insight or help is much appreciated. Have been stumped for a long time as I have been learning this online on my own.
In OpenGL the projection matrix turns from a right handed system to a left handed system. See Right-hand rule). This is accomplished by mirroring the z axis.
The terms in the 3rd column have to be inverted (- (near+far) / (near-far) respectively - (2*near*far) / (near-far)):
List projection = [
[1 / (aspect * tan(fov/2)), 0, 0, 0],
[0, 1 / (tan(fov/2)), 0, 0],
[0, 0, - (near+far) / (near-far), - (2*near*far) / (near-far)],
[0, 0, -1, 0]
];
The perspective projection matrix defines a Viewing frustum. It defines a 3 dimensional space (clip space) which is projected on the 2 dimensional viewport.
In OponGL all the geometry which is not in clip space is clipped. You have to ensure that the geometry is in between the near and far plane.

How to apply CIEdgePreserveUpsampleFilter on CIImage?

I am following this WWDC lecture.
In the lecture he mentions a filter named "CIEdgePreserveUpsampleFilter" that makes the edges more preserved and upsampled.
I am trying to apply this on my CIImage and I get an uninitialized result for the Image and crashes.
This is the code I am using and an example of how I try to apply the filter (which is obviously wrong). I just cannot find any related instructions for applying this filter, I just know I want its results on my image.
I comment next to where I try to apply the filter, and what happens when I do it.
func createMask(for depthImage: CIImage, withFocus focus: CGFloat, andScale scale: CGFloat, andSlope slope: CGFloat = 4.0, andWidth width: CGFloat = 0.1) -> CIImage {
let s1 = slope
let s2 = -slope
let filterWidth = 2 / slope + width
let b1 = -s1 * (focus - filterWidth / 2)
let b2 = -s2 * (focus + filterWidth / 2)
let mask0 = depthImage
.applyingFilter("CIColorMatrix", withInputParameters: [
"inputRVector": CIVector(x: s1, y: 0, z: 0, w: 0),
"inputGVector": CIVector(x: 0, y: s1, z: 0, w: 0),
"inputBVector": CIVector(x: 0, y: 0, z: s1, w: 0),
"inputBiasVector": CIVector(x: b1, y: b1, z: b1, w: 0)])
.applyingFilter("CIColorClamp").applyingFilter("CIEdgePreserveUpsampleFilter") //returns uninitialized image
let mask1 = depthImage
.applyingFilter("CIColorMatrix", withInputParameters: [
"inputRVector": CIVector(x: s2, y: 0, z: 0, w: 0),
"inputGVector": CIVector(x: 0, y: s2, z: 0, w: 0),
"inputBVector": CIVector(x: 0, y: 0, z: s2, w: 0),
"inputBiasVector": CIVector(x: b2, y: b2, z: b2, w: 0)])
.applyingFilter("CIColorClamp")
var combinedMask = mask0.applyingFilter("CIEdgePreserveUpsampleFilter", withInputParameters: ["inputBackgroundImage" : mask1]) //complete crash
if PortraitModel.sharedInstance.filterArea == .front {
combinedMask = combinedMask.applyingFilter("CIColorInvert")
}
let mask = combinedMask.applyingFilter("CIBicubicScaleTransform", withInputParameters: [kCIInputScaleKey: scale])
return mask
}
The runtime headers and some usage code I've found seems to suggest that CIEdgePreserveUpsampleFilter does not take a inputBackgroundImage parameter, but rather inputSmallImage.
See https://gist.github.com/HarshilShah/ca0e18db01ce250fd308ab5acc99a9d0