Pinching image on edges as a custom CIWarpKernel does not produces results as expected - ios

I have developed a custom CIWarpKernel which is the transposition of my Numbers model design as follows:
The cell for positive y is: SIN($A2×PI()÷2)×(−COS(B$1×PI())×($A2+1)÷$W$3+SIN($A2 ×PI()÷2)) where $A2 is y, B$1 is x and $W$3 is the center stretching factor.
The code is as follows:
kernel vec2 panoramaDistortion (vec2 center) {
float pi = 3.141592653589793;
vec2 t = destCoord();
float x = t.x / center.x - 1.0; // x ∈ -1...1
float y = t.y / center.y - 1.0; // y ∈ -1...1
float rx = x;
float delta = 50.0;
float siny = sin(y * pi / 2.0);
// See my model in Numbers: Aladdin PanoramPinch CIKernel file where $a2 = x and b$1 = y
// sin($a2×pi()÷2)×(−cos(b$1×pi())×($a2+1)÷$w$3+sin($a2 ×pi()÷$w$5))
// sin(y×pi()÷2)×(−cos(x×pi())×(y+1)÷$w$3+sin(y×pi()÷2))
// sin($a22×pi()÷2)×(−cos(b$1×pi())×abs(1−$a22)÷$w$3−sin($a22 ×pi()÷$w$5))
float ry =
y >= 0.0 ?
siny * (-cos(x * pi) * (y + 1.0) / delta + siny)
: siny * (-cos(x * pi) * (1.0 - y) / delta - siny)
;
return vec2(center.x * (rx + 1.0), center.y * (ry + 1.0));
}
The issue I have is that, though the transposition is 100% exact, I don't get the same result I have in my model. See the resulting warping of tiled-image:
How it comes I have the dilatation at the center y=0 and at the upper- and bottom- sides?
For information, my tiled-image is as follows:

Related

Rendering Lines with Bezier Curves in DX11

I want to input control points through the tessellation stages and output them as bent lines.
I expand the lines into billboarded quads in the geometry shader.
Right now I input a bunch of random vertices with a control point number of 4.
I assume the bending is done in the domain shader so I use one of the uv coordinates unique for that stage as a t value for a bezier function that takes in 4 world position coordinates.
However the lines remain straight. And I don't know what I am missing.
My code looks like this:
Domain Shader:
float3 bezier( float3 p0, float3 p1, float3 p2, float3 p3, float u)
{
float B0 = (1. - u) * (1. - u) * (1. - u);
float B1 = 3. * u * (1. - u) * (1. - u);
float B2 = 3. * u * u * (1. - u);
float B3 = u * u * u;
float3 p = B0 * p0 + B1 * p1 + B2 * p2 + B3 * p3;
return p;
}
float t = uv.x;
float3 pos = bezier(inp[0].worldPos, inp[1].worldPos, inp[2].worldPos, inp[3].worldPos, t);
Could the problem be that the vertex points I input are not forming curves? Right now I just take a mesh such as a plane and take the vertices from there.
The detail factor in the hull shader is 16. Density factor varies by distance.
I don't know what else is relevant. If you need more information let me know. I hope I made the question clear, I have googled it but can't seem to find the error in my own code.
See the SimpleBezier sample:
float4 BernsteinBasis(float t)
{
float invT = 1.0f - t;
return float4(invT * invT * invT,
3.0f * t * invT * invT,
3.0f * t * t * invT,
t * t * t);
}
float4 dBernsteinBasis(float t)
{
float invT = 1.0f - t;
return float4(-3 * invT * invT,
3 * invT * invT - 6 * t * invT,
6 * t * invT - 3 * t * t,
3 * t * t);
}
float3 EvaluateBezier(const OutputPatch< HS_OUTPUT, OUTPUT_PATCH_SIZE > BezPatch,
float4 BasisU,
float4 BasisV)
{
float3 value = float3(0, 0, 0);
value = BasisV.x * (BezPatch[0].pos * BasisU.x + BezPatch[1].pos * BasisU.y + BezPatch[2].pos * BasisU.z + BezPatch[3].pos * BasisU.w);
value += BasisV.y * (BezPatch[4].pos * BasisU.x + BezPatch[5].pos * BasisU.y + BezPatch[6].pos * BasisU.z + BezPatch[7].pos * BasisU.w);
value += BasisV.z * (BezPatch[8].pos * BasisU.x + BezPatch[9].pos * BasisU.y + BezPatch[10].pos * BasisU.z + BezPatch[11].pos * BasisU.w);
value += BasisV.w * (BezPatch[12].pos * BasisU.x + BezPatch[13].pos * BasisU.y + BezPatch[14].pos * BasisU.z + BezPatch[15].pos * BasisU.w);
return value;
}
[domain("quad")]
DS_OUTPUT BezierDS(HS_CONSTANT_DATA_OUTPUT input,
float2 UV : SV_DomainLocation,
const OutputPatch< HS_OUTPUT, OUTPUT_PATCH_SIZE > BezPatch)
{
float4 BasisU = BernsteinBasis(UV.x);
float4 BasisV = BernsteinBasis(UV.y);
float4 dBasisU = dBernsteinBasis(UV.x);
float4 dBasisV = dBernsteinBasis(UV.y);
float3 worldPos = EvaluateBezier(BezPatch, BasisU, BasisV);
float3 tangent = EvaluateBezier(BezPatch, dBasisU, BasisV);
float3 biTangent = EvaluateBezier(BezPatch, BasisU, dBasisV);
float3 normal = normalize(cross(tangent, biTangent));
DS_OUTPUT output;
output.pos = mul(float4(worldPos, 1), g_mViewProjection);
output.worldPos = worldPos;
output.normal = normal;
return output;
}
https://github.com/microsoft/Xbox-ATG-Samples/tree/master/PCSamples/IntroGraphics/SimpleBezierPC
https://github.com/microsoft/Xbox-ATG-Samples/tree/master/PCSamples/IntroGraphics/SimpleBezierPC12

Line Pixellating

Using Metal I am drawing line using Bezier Curves using four points. I am using nearly 1500 triangles for the lines. The line is Pixellated. How can i reduce pixellated.
vertex VertexOutBezier bezier_vertex(constant BezierParameters *allParams[[buffer(0)]],
constant GlobalParameters& globalParams[[buffer(1)]],
uint vertexId [[vertex_id]],
uint instanceId [[instance_id]])
{
float t = (float) vertexId / globalParams.elementsPerInstance;
rint(t);
BezierParameters params = allParams[instanceId];
float lineWidth = (1 - (((float) (vertexId % 2)) * 2.0)) * params.lineThickness;
float2 a = params.a;
float2 b = params.b;
float cx = distance(a , b);
float2 p1 = params.p1 * 3.0; // float2 p1 = params.p1 * 3.0;
float2 p2 = params.p2 * 3.0; // float2 p2 = params.p2 * 3.0;
float nt = 1.0f - t;
float nt_2 = nt * nt;
float nt_3 = nt_2 * nt;
float t_2 = t * t;
float t_3 = t_2 * t;
// Calculate a single point in this Bezier curve:
float2 point = a * nt_3 + p1 * nt_2 * t + p2 * nt * t_2 + b * t_3;
float2 tangent = -3.0 * a * nt_2 + p1 * (1.0 - 4.0 * t + 3.0 * t_2) + p2 * (2.0 * t - 3.0 * t_2) + 3 * b * t_2;
tangent = (float2(-tangent.y , tangent.x ));
VertexOutBezier vo;
vo.pos.xy = point + (tangent * (lineWidth / 2.0f));
vo.pos.zw = float2(0, 1);
vo.color = params.color;
return vo;
}
You need to enable MSAA (multisample anti-aliasing). How you do this depends on your exact Metal view configuration, but the easiest way is if you're using MTKView. To enable MSAA in an MTKView, all you have to do is:
metalView.sampleCount = 4
Then, when you configure your MTLRenderPipelineDescriptor before calling makeRenderPipelineState(), add the following:
pipelineDescriptor.sampleCount = 4
This should greatly improve the quality of your curves and reduce pixelation. It does come with a performance cost however, as the GPU has to do substantially more work to render your frame.

Convert cv::Vec4f line to cv::Vec2f

I have a pair of Cartesian coordinates that represent a line in an image. I would like to convert this line to polar form and draw it over the image.
e.g
cv::Vec4f line {10,20,60,70};
float x1 = line[0];
float y1 = line[1];
float x2 = line[2];
float y2 = line[3];
I want this line to be represented in cv::Vec2f form(rho,theta).
Taking care of rho & theta with all possible slopes.
Given are the image dimensions :: w and h;
w = image.cols
h = image.rows
How can I achieve this.
N.B: We can also assume that the line can be an extended one running across the image.
for (size_t i = 0; i < lines.size(); i++)
{
int x1 = lines[i][0];
int y1 = lines[i][1];
int x2 = lines[i][2];
int y2 = lines[i][3];
float d = sqrt(((y1-y2)*(y1-y2)) + ((x2-x1)*(x2-x1)) );
float rho = (y1*x2 - y2*x1)/d;
float theta = atan2(x2 - x1,y1-y2) ;
if(rho < 0){
theta *= -1;
rho *= -1;
}
linv2f.push_back(cv::Vec2f(rho,theta));
}
The above approach doesnt give me results when I plot the lines I dont get the lines that are overlapping their original vec4f form.
I use this to convert vec2f to vec4f for testing :
cv::Vec4f cvtVec2fLine(const cv::Vec2f& data, const cv::Mat& img)
{
float const rho = data[0];
float const theta = data[1];
cv::Point pt1,pt2;
if((theta < CV_PI/4. || theta > 3. * CV_PI/4.)){
pt1 = cv::Point(rho / std::cos(theta), 0);
pt2 = cv::Point( (rho - img.rows * std::sin(theta))/std::cos(theta), img.rows);
}else {
pt1 = cv::Point(0, rho / std::sin(theta));
pt2 = cv::Point(img.cols, (rho - img.cols * std::cos(theta))/std::sin(theta));
}
cv::Vec4f l;
l[0] = pt1.x;
l[1] = pt1.y;
l[2] = pt2.x;
l[3] = pt2.y;
return l;
}
rho-theta equation has form
x * Cos(Theta) + y * Sin(Theta) - Rho = 0
We want to represent equation 'by two points' into rho-theta form (page 92 in pdf here). If we have
x * A + y * B - C = 0
and need coefficients in trigonometric form, we can divide all equation by magnitude of (A,B) coefficient vector.
D = Length(A,B) = Math.Hypot(A,B)
x * A/D + y * B/D - C/D = 0
note that (A/D)^2 + (B/D)^2 = 1 - basic trigonometric equality, so we can consider A/D and B/D as cosine and sine of some angle theta.
Your line equation is
(y-y1) * (x2-x1) - (x-x1) * (y2-y1) = 0
or
x * (y1-y2) + y * (x2-x1) - (y1 * x2 - y2 * x1) = 0
let
D = Sqrt((y1-y2)^2 + (x2-x1)^2)
so
Theta = ArcTan2(x2-x1, y1-y2)
Rho = (y1 * x2 - y2 * x1) / D
edited
If Rho is negative, change sign of Rho and shift Theta by Pi
Example:
x1=1,y1=0, x2=0,y2=1
Theta = atan2(-1,-1)=-3*Pi/4
D=Sqrt(2)
Rho=-Sqrt(2)/2 negative =>
Rho = Sqrt(2)/2
Theta = Pi/4
Back substitutuon - find points of intersection with axes
0 * Sqrt(2)/2 + y0 * Sqrt(2)/2 - Sqrt(2)/2 = 0
x=0 y=1
x0 * Sqrt(2)/2 + 0 * Sqrt(2)/2 - Sqrt(2)/2 = 0
x=1 y=0

Bilateration with iBeacons

I am trying to use multiple iBeacons to track the user's location in iOS. I know this can be done (somewhat) using 3 beacons and trilateration, but I would like to do it with two (bilateration). I know that I will likely end up with two answers. Does anyone know of a simple way to accomplish this, given the (x,y) location of the beacons (relative to the room), and an averaged RSSI from each beacon?
I have this code for trilateration that I altered to objective-c from javascript:
- (CGPoint)getTrilaterationWithBeacon1:(BBBeacon *)beacon1 Beacon2:(BBBeacon *)beacon2 Beacon3:(BBBeacon *)beacon3 {
float xa = beacon1.x;
float ya = beacon1.y;
float xb = beacon2.x;
float yb = beacon2.y;
float xc = beacon3.x;
float yc = beacon3.y;
float ra = beacon1.distance;
float rb = beacon2.distance;
float rc = beacon3.distance;
float S = (pow(xc, 2.) - pow(xb, 2.) + pow(yc, 2.) - pow(yb, 2.) + pow(rb, 2.) - pow(rc, 2.)) / 2.0;
float T = (pow(xa, 2.) - pow(xb, 2.) + pow(ya, 2.) - pow(yb, 2.) + pow(rb, 2.) - pow(ra, 2.)) / 2.0;
float y = ((T * (xb - xc)) - (S * (xb - xa))) / (((ya - yb) * (xb - xc)) - ((yc - yb) * (xb - xa)));
float x = ((y * (ya - yb)) - T) / (xb - xa);
CGPoint point = CGPointMake(x, y);
return point;
}
So this is the code I ended up using, thanks to ChuckCottrill's suggestion that I look for a formula to calculate intersection of two circles. It is modified from a C version I found online here: http://paulbourke.net/geometry/circlesphere/tvoght.c
The results are somewhat inconsistent due to the inconsistency of the RSSI values returned from the iBeacons.
I will still need to add code to select the correct point somehow (it gives two results).
- (CGPoint)getBilaterationWithBeacon1:(BBBeacon *)beacon1 Beacon2:(BBBeacon *)beacon2 {
float x0 = beacon1.locationX;
float y0 = beacon1.locationY;
float r0 = beacon1.filteredDistance;
float x1 = beacon2.locationX;
float y1 = beacon2.locationY;
float r1 = beacon2.filteredDistance;
float a, dx, dy, d, h, rx, ry;
float x2, y2;
/* dx and dy are the vertical and horizontal distances between
* the circle centers.
*/
dx = x1 - x0;
dy = y1 - y0;
/* Determine the straight-line distance between the centers. */
d = sqrt((dy*dy) + (dx*dx));
/* Check for solvability. */
if (d > (r0 + r1)) {
/* no solution. circles do not intersect. */
return CGPointMake(-1, -1);
}
if (d < abs(r0 - r1)) {
/* no solution. one circle is contained in the other */
return CGPointMake(-1, -1);
}
/* 'point 2' is the point where the line through the circle
* intersection points crosses the line between the circle
* centers.
*/
/* Determine the distance from point 0 to point 2. */
a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
/* Determine the coordinates of point 2. */
x2 = x0 + (dx * a/d);
y2 = y0 + (dy * a/d);
/* Determine the distance from point 2 to either of the
* intersection points.
*/
h = sqrt((r0*r0) - (a*a));
/* Now determine the offsets of the intersection points from
* point 2.
*/
rx = -dy * (h/d);
ry = dx * (h/d);
/* Determine the absolute intersection points. */
float xi = x2 + rx;
float xi_prime = x2 - rx;
float yi = y2 + ry;
float yi_prime = y2 - ry;
CGPoint point1 = CGPointMake(xi, yi);
CGPoint point2 = CGPointMake(xi_prime, yi_prime);
//pick one
return point2;
}

iOS Core Data To Query Against Geospatial Data Set

I'm using the Core Data Framework to manage a set of accounts which also include geospatial (GPS) coordinate data for each account. How can I query against this data based on position of the device to get a list of accounts within x feet and list them in order of distance?
to get you started, here's a method i use in my iOS app that returns the distance in meters between two CLLocationCoordinate2D locations, assuming the Google Spherical Mercator Projection (if you want to use another projection, you can specify the appropriate flattening ratio value (f) and semi-major axis value (a). if you want the forward and backward azimuth values between the coordinates, you can uncomment and return the faz and baz values along with the distance by defining your own struct. this method can be used to add the distance to each of your 'account' objects and the current location being reported by your CLLocationManager object, then you could easily sort and filter an array of account objects based on their distances.
based on code by Gerald Evenden located here: http://article.gmane.org/gmane.comp.gis.proj-4.devel/3478
#define PI 3.141592653589793238462643
#define EPS 5e-14
#define DEG_TO_RAD 0.0174532925199432958
// returns the geodesic distance in meters between two coordinates based on the google spherical mercator projection.
- (int) geodesicDistanceFromCoordinate: (CLLocationCoordinate2D) fromCoord toCoordinate: (CLLocationCoordinate2D) toCoord {
double c, d, e, r, x, y, sa, cx, cy, cz, sx, sy, c2a, cu1, cu2, su1, tu1, tu2, ts, phi1, lam1, phi2, lam2, f, baz, faz, s, a;
phi1 = fromCoord.latitude * DEG_TO_RAD;
lam1 = fromCoord.longitude * DEG_TO_RAD;
phi2 = toCoord.latitude * DEG_TO_RAD;
lam2 = toCoord.longitude * DEG_TO_RAD;
f = 0; //google's spherical mercator projection has no flattening
a = 6378137; //earth's axis in meters used in google's projection
r = 1. - f;
tu1 = r * tan(phi1);
tu2 = r * tan(phi2);
cu1 = 1. / sqrt(tu1 * tu1 + 1.);
su1 = cu1 * tu1;
cu2 = 1. / sqrt(tu2 * tu2 + 1.);
ts = cu1 * cu2;
baz = ts * tu2;
faz = baz * tu1;
x = lam2 - lam1;
do {
sx = sin(x);
cx = cos(x);
tu1 = cu2 * sx;
tu2 = baz - su1 * cu2 * cx;
sy = sqrt(tu1 * tu1 + tu2 * tu2);
cy = ts * cx + faz;
y = atan2(sy, cy);
sa = ts * sx / sy;
c2a = -sa * sa + 1.;
cz = faz + faz;
if (c2a > 0.)
cz = -cz / c2a + cy;
e = cz * cz * 2. - 1.;
c = ((c2a * -3. + 4.) * f + 4.) * c2a * f / 16.;
d = x;
x = ((e * cy * c + cz) * sy * c + y) * sa;
x = (1. - c) * x * f + lam2 - lam1;
} while (fabs(d - x) > EPS);
//forward azimuth faz = atan2(tu1, tu2);
//backward azimuth baz = atan2(cu1 * sx, baz * cx - su1 * cu2) + PI;
x = sqrt((1. / r / r - 1.) * c2a + 1.) + 1.;
x = (x - 2.) / x;
c = (x * x / 4. + 1.) / (1. - x);
d = (x * .375 * x - 1.) * x;
s = ((((sy * sy * 4. - 3.) * (1. - e - e) * cz * d / 6. - e * cy) * d / 4. + cz) * sy * d + y) * c * r;
return (int)(s * a);
}

Resources