iOS Core Data To Query Against Geospatial Data Set - ios

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);
}

Related

How to get XY value from ct in Philips Hue?

How to get XY value from ct.
Ex: ct = 217, I want to get x="0.3127569", y= "0.32908".
I'm able to convert XY value into ct value using this below code.
float R1 = [hue[0] floatValue];
float S1 = [hue[1] floatValue];
float result = ((R1-0.332)/(S1-0.1858));
NSString *ctString = [NSString stringWithFormat:#"%f", ((-449*result*result*result)+(3525*result*result)-(6823.3*result)+(5520.33))];
float micro2 = (float) (1 / [ctString floatValue] * 1000000);
NSString *ctValue = [NSString stringWithFormat:#"%f", micro2];
ctValue = [NSString stringWithFormat:#"%d", [ctValue intValue]];
if ([ctValue integerValue] < 153) {
ctValue = [NSString stringWithFormat:#"%d", 153];
}
Now I want reverse value, which is from ct to XY.
On Phillips HUE
2000K maps to 500 and 6500K maps to 153 given in ct as color temperature but can be thought as actually being Mired.
Mired means micro reciprocal degree wikipedia.
ct is possibly used because it is not 100% Mired. Quite sure Phillips uses a lookup table as a lot CIE algorithms do because there are just 347 indexes in this range from 153 to 500.
The following is not a solution, it's just simple concept of a lookup table.
And as the CIE 1931 xy to CCT Formula by McCamy suggests found here it is possible to use a lookup table to find x and y as well.
A table can be found here but i am not sure if that is the right lookup table.
reminder so the following is not a solution, but to find an reverse algo the code may help.
typedef int Kelvin;
typedef float Mired;
Mired linearMiredByKelvin(Kelvin k) {
if (k==0) return 0;
return 1000000.0/k;
}
-(void)mired {
Mired miredMin = 2000.0/13.0; // 153,84 = reciprocal 6500K
Mired miredMax = 500.0; // 500,00 = reciprocal 2000K
Mired lookupMiredByKelvin[6501]; //max 6500 Kelvin + 1 safe index
//Kelvin lookupKelvinByMired[501]; //max 500 Mired + 1 safe index
// dummy stuff, empty unused table space
for (Kelvin k = 0; k < 2000; k++) {
lookupMiredByKelvin[k] = 0;
}
//for (Mired m = 0.0; m < 154.0; m++) {
// lookupKelvinByMired[(int)m] = 0;
//}
for (Kelvin k=2000; k<6501; k++) {
Mired linearMired = linearMiredByKelvin(k);
float dimm = (linearMired - miredMin) / ( miredMax - miredMin);
Kelvin ct = (Kelvin)(1000000.0/(dimm*miredMax - dimm*miredMin + miredMin));
lookupMiredByKelvin[k] = linearMiredByKelvin(ct);
if (k==2000 || k==2250 || k==2500 || k==2750 ||
k==3000 || k==3250 || k==3500 || k==3750 ||
k==4000 || k==4250 || k==4500 || k==4750 ||
k==5000 || k==5250 || k==5500 || k==5750 ||
k==6000 || k==6250 || k==6500 || k==6501 )
fprintf(stderr,"%d %f %f\n",ct, dimm, lookupMiredByKelvin[k]);
}
}
at least this is proof that x and y will not sit on a simple vector.
CCT means correlated colour temperature and like the implementation in the question shows can be calculated via n= (x-0.3320)/(0.1858-y); CCT = 437*n^3 + 3601*n^2 + 6861*n + 5517. (after McCamy)
but a cct=217 is out of range of above link'ed lookup table.
following the idea in this git-repo from colour-science
and ported to C it could look like..
void CCT_to_xy_CIE_D(float cct) {
//if (CCT < 4000 || CCT > 25000) fprintf(stderr, "Correlated colour temperature must be in domain, unpredictable results may occur! \n");
float x = calculateXviaCCT(cct);
float y = calculateYviaX(x);
NSLog(#"cct=%f x%f y%f",cct,x,y);
}
float calculateXviaCCT(float cct) {
float cct_3 = pow(cct, 3); //(cct*cct*cct);
float cct_2 = pow(cct, 2); //(cct*cct);
if (cct<=7000)
return -4.607 * pow(10, 9) / cct_3 + 2.9678 * pow(10, 6) / cct_2 + 0.09911 * pow(10, 3) / cct + 0.244063;
return -2.0064 * pow(10, 9) / cct_3 + 1.9018 * pow(10, 6) / cct_2 + 0.24748 * pow(10, 3) / cct + 0.23704;
}
float calculateYviaX(float x) {
return -3.000 * pow(x, 2) + 2.870 * x - 0.275;
}
CCT_to_xy_CIE_D(6504.38938305); //proof of concept
//cct=6504.389160 x0.312708 y0.329113
CCT_to_xy_CIE_D(217.0);
//cct=217.000000 x-387.131073 y-450722.750000
// so for sure Phillips hue temperature given in ct between 153-500 is not a good starting point
//but
CCT_to_xy_CIE_D(2000.0);
//cct=2000.000000 x0.459693 y0.410366
this seems to work fine with CCT between 2000 and 25000, but maybe confusing is CCT is given in Kelvin here.
EDIT
This has been through so many revisions and ideas. To keep it simple I edited most of that out and just give you the final result.
This fits your function perfectly except for a region in the middle (temp from 256 to 316) where it deviates a bit.
The problem with your function is that it has approximately infinite solutions, so to solve it nicely you need more constraints, but what? Ol Sen's reference https://www.waveformlighting.com/tech/calculate-color-temperature-cct-from-cie-1931-xy-coordinates discusses it in some detail and then mentions that you want a Duv to be zero. It also gives a way to calculate Duv and so I added that to my optimiser and voila!
Nice and smooth. The optimiser now solves for x and y that both satisfies your function and also minimises Duv.
To get it to work nicely I had to scale Duv quite a bit. That page mentions that Duv should be very small so I think this is a good thing. Also, as the temp increases the scaling should to help the optimiser.
Below prints from 153 to 500.
#import <Foundation/Foundation.h>
// Function taken from your code
// Simplified a bit
int ctFuncI ( float x, float y )
{
// float R1 = [hue[0] floatValue];
// float S1 = [hue[1] floatValue];
float result = (x-0.332)/(y-0.1858);
float cubic = - 449 * result * result * result + 3525 * result * result - 6823.3 * result + 5520.33;
float micro2 = 1 / cubic * 1000000;
int ct = ( int )( micro2 + 0.5 );
if ( ct < 153 )
{
ct = 153;
}
return ct;
}
// Need this
// Float version of your code
float ctFuncF ( float x, float y )
{
// float R1 = [hue[0] floatValue];
// float S1 = [hue[1] floatValue];
float result = (x-0.332)/(y-0.1858);
float cubic = - 449 * result * result * result + 3525 * result * result - 6823.3 * result + 5520.33;
return 1000000 / cubic;
}
// We need an additional constraint
// https://www.waveformlighting.com/tech/calculate-duv-from-cie-1931-xy-coordinates
// Given x, y calculate Duv
// We want this to be 0
float duv ( float x, float y )
{
float f = 1 / ( - 2 * x + 12 * y + 3 );
float u = 4 * x * f;
float v = 6 * y * f;
// I'm typing float but my heart yells double
float k6 = -0.00616793;
float k5 = 0.0893944;
float k4 = -0.5179722;
float k3 = 1.5317403;
float k2 = -2.4243787;
float k1 = 1.925865;
float k0 = -0.471106;
float du = u - 0.292;
float dv = v - 0.24;
float Lfp = sqrt ( du * du + dv * dv );
float a = acos( du / Lfp );
float Lbb = k6 * pow ( a, 6 ) + k5 * pow( a, 5 ) + k4 * pow( a, 4 ) + k3 * pow( a, 3 ) + k2 * pow(a,2) + k1 * a + k0;
return Lfp - Lbb;
}
// Solver!
// Returns iterations
int ctSolve ( int ct, float * x, float * y )
{
int iter = 0;
float dx = 0.001;
float dy = 0.001;
// Error
// Note we scale duv a bit
// Seems the higher the temp, the higher scale we require
// Also note the jump at 255 ...
float s = 1000 * ( ct > 255 ? 10 : 1 );
float d = fabs( ctFuncF ( * x, * y ) - ct ) + s * fabs( duv ( * x, * y ) );
// Approx
while ( d > 0.5 && iter < 250 )
{
iter ++;
dx *= fabs( ctFuncF ( * x + dx, * y ) - ct ) + s * fabs( duv ( * x + dx, * y ) ) < d ? 1.2 : - 0.5;
dy *= fabs( ctFuncF ( * x, * y + dy ) - ct ) + s * fabs( duv ( * x, * y + dy ) ) < d ? 1.2 : - 0.5;
* x += dx;
* y += dy;
d = fabs( ctFuncF ( * x, * y ) - ct ) + s * fabs( duv ( * x, * y ) );
}
return iter;
}
// Tester
int main(int argc, const char * argv[]) {
#autoreleasepool
{
// insert code here...
NSLog(#"Hello, World!");
float x, y;
int sume = 0;
int sumi = 0;
for ( int ct = 153; ct <= 500; ct ++ )
{
// Initial guess
x = 0.4;
y = 0.4;
// Approx
int iter = ctSolve ( ct, & x, & y );
// CT and error
int ctEst = ctFuncI ( x, y );
int e = ct - ctEst;
// Diagnostics
sume += abs ( e );
sumi += iter;
// Print out results
NSLog ( #"want ct = %d x = %f y = %f got ct %d in %d iter error %d", ct, x, y, ctEst, iter, e );
}
NSLog ( #"Sum of abs errors %d iterations %d", sume, sumi );
}
return 0;
}
To use it, do as below.
// To call it, init x and y to some guess
float x = 0.4;
float y = 0.4;
// Then call solver with your temp
int ct = 217;
ctSolve( ct, & x, & y ); // Note you pass references to x and y
// Done, answer now in x and y
a bit more compact answer and functions to convert back and forth..
beware there are rounding issues because McCamy's formula relies and mathematical assumptions. And so the backward calculation does also.
if you want to find more results search directly for "n= (x-0.3320)/(0.1858-y); CCT = 437*n^3 + 3601*n^2 + 6861*n + 5517" there are plenty of different methods to convert back and forth.
so here Phillips-Hue #[#x,#y] to Phillips-ct,Phillips-ct to CCT, CCT to x,y
void CCT_to_xy_CIE_D(float cct) {
//if (CCT < 4000 || CCT > 25000) fprintf(stderr, "Correlated colour temperature must be in domain, unpredictable results may occur! \n");
float x = calculateXviaCCT(cct);
float y = calculateYviaX(x);
fprintf(stderr,"cct=%f x%f y%f",cct,x,y);
}
float calculateXviaCCT(float cct) {
float cct_3 = pow(cct, 3); //(cct*cct*cct);
float cct_2 = pow(cct, 2); //(cct*cct);
if (cct<=7000.0)
return -4.607 * pow(10, 9) / cct_3 + 2.9678 * pow(10, 6) / cct_2 + 0.09911 * pow(10, 3) / cct + 0.244063;
return -2.0064 * pow(10, 9) / cct_3 + 1.9018 * pow(10, 6) / cct_2 + 0.24748 * pow(10, 3) / cct + 0.23704;
}
float calculateYviaX(float x) {
return -3.000 * x*x + 2.870 * x - 0.275;
}
int calculate_PhillipsHueCT_withCCT(float cct) {
if (cct>6500.0) return 2000.0/13.0;
if (cct<2000.0) return 500.0;
//return (float) (1 / cct * 1000000); // same as..
return 1000000 / cct;
}
float calculate_CCT_withPhillipsHueCT(float ct) {
if (ct == 0.0) return 0.0;
return 1000000 / ct;
}
float calculate_CCT_withHueXY(NSArray *hue) {
float x = [hue[0] floatValue]; //R1
float y = [hue[1] floatValue]; //S1
//x = 0.312708; y = 0.329113;
float n = (x-0.3320)/(0.1858-y);
float cct = 437.0*n*n*n + 3601.0*n*n + 6861.0*n + 5517.0;
return cct;
}
// MC Camy formula n=(x-0.3320)/(0.1858-y); cct = 437*n^3 + 3601*n^2 + 6861*n + 5517;
-(void)testPhillipsHueCt_backAndForth {
NSArray *hue = #[#(0.312708),#(0.329113)];
float cct = calculate_CCT_withHueXY(hue);
float ct = calculate_PhillipsHueCT_withCCT(cct);
NSLog(#"ct %f",ct);
CCT_to_xy_CIE_D(cct); // check
CCT_to_xy_CIE_D(6504.38938305); //proof of concept
CCT_to_xy_CIE_D(2000.0);
CCT_to_xy_CIE_D(calculate_CCT_withPhillipsHueCT(217.0));
}

Is there a way to check if an XYZ triplet is a valid color?

The XYZ color space encompasses all possible colors, not just those which can be generated by a particular device like a monitor. Not all XYZ triplets represent a color that is physically possible. Is there a way, given an XYZ triplet, to determine if it represents a real color?
I wanted to generate a CIE 1931 chromaticity diagram (seen bellow) for myself, but wasn't sure how to go about it. It's easy to, for example, take all combinations of sRGB triplets and then transform them into the xy coordinates of the chromaticity diagram and then plot them. You cannot use this same approach in the XYZ color space though since not all combinations are valid colors. So far the best I have come up with is a stochastic approach, where I generate a random spectral distribution by summing a random number of random Gaussians, then converting it to XYZ using the standard observer functions.
Having thought about it a little more I felt the obvious solution is to generate a list of xy points around the edge of spectral locus, corresponding to pure monochromatic colors. It seems to me that this can be done by directly inputting the visible frequencies (~380-780nm) into the CIE XYZ standard observer color matching functions. Treating these points like a convex polygon you could determine if a point is within the spectral locus using one algorithm or another. In my case, since what I really wanted to do is simply generate the chromaticity diagram, I simply input these points into a graphics library's polygon drawing routine and then for each pixel of the polygon I can transform it into sRGB.
I believe this solution is similar to the one used by the library that Kel linked in a comment. I'm not entirely sure, as I am not familiar with Python.
function RGBfromXYZ(X, Y, Z) {
const R = 3.2404542 * X - 1.5371385 * Y - 0.4985314 * Z
const G = -0.969266 * X + 1.8760108 * Y + 0.0415560 * Z
const B = 0.0556434 * X - 0.2040259 * Y + 1.0572252 * Z
return [R, G, B]
}
function XYZfromYxy(Y, x, y) {
const X = Y / y * x
const Z = Y / y * (1 - x - y)
return [X, Y, Z]
}
function srgb_from_linear(x) {
if (x <= 0.0031308) {
return x * 12.92
} else {
return 1.055 * Math.pow(x, 1/2.4) - 0.055
}
}
// Analytic Approximations to the CIE XYZ Color Matching Functions
// from Sloan http://jcgt.org/published/0002/02/01/paper.pdf
function xFit_1931(x) {
const t1 = (x - 442) * (x < 442 ? 0.0624 : 0.0374)
const t2 = (x -599.8) * (x < 599.8 ? 0.0264 : 0.0323)
const t3 = (x - 501.1) * (x < 501.1 ? 0.0490 : 0.0382)
return 0.362 * Math.exp(-0.5 * t1 * t1) + 1.056 * Math.exp(-0.5 * t2 * t2) - 0.065 * Math.exp(-0.5 * t3 * t3)
}
function yFit_1931(x) {
const t1 = (x - 568.8) * (x < 568.8 ? 0.0213 : 0.0247)
const t2 = (x - 530.9) * (x < 530.9 ? 0.0613 : 0.0322)
return 0.821 * Math.exp(-0.5 * t1 * t1) + 0.286 * Math.exp(-0.5 * t2 * t2)
}
function zFit_1931(x) {
const t1 = (x - 437) * (x < 437 ? 0.0845 : 0.0278)
const t2 = (x - 459) * (x < 459 ? 0.0385 : 0.0725)
return 1.217 * Math.exp(-0.5 * t1 * t1) + 0.681 * Math.exp(-0.5 * t2 * t2)
}
const canvas = document.createElement("canvas")
document.body.append(canvas)
canvas.width = canvas.height = 512
const ctx = canvas.getContext("2d")
const locus_points = []
for (let i = 440; i < 650; ++i) {
const [X, Y, Z] = [xFit_1931(i), yFit_1931(i), zFit_1931(i)]
const x = (X / (X + Y + Z)) * canvas.width
const y = (Y / (X + Y + Z)) * canvas.height
locus_points.push([x, y])
}
ctx.beginPath()
ctx.moveTo(...locus_points[0])
locus_points.slice(1).forEach(point => ctx.lineTo(...point))
ctx.closePath()
ctx.fill()
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
for (let y = 0; y < canvas.height; ++y) {
for (let x = 0; x < canvas.width; ++x) {
const alpha = imageData.data[(y * canvas.width + x) * 4 + 3]
if (alpha > 0) {
const [X, Y, Z] = XYZfromYxy(1, x / canvas.width, y / canvas.height)
const [R, G, B] = RGBfromXYZ(X, Y, Z)
const r = Math.round(srgb_from_linear(R / Math.sqrt(R**2 + G**2 + B**2)) * 255)
const g = Math.round(srgb_from_linear(G / Math.sqrt(R**2 + G**2 + B**2)) * 255)
const b = Math.round(srgb_from_linear(B / Math.sqrt(R**2 + G**2 + B**2)) * 255)
imageData.data[(y * canvas.width + x) * 4 + 0] = r
imageData.data[(y * canvas.width + x) * 4 + 1] = g
imageData.data[(y * canvas.width + x) * 4 + 2] = b
}
}
}
ctx.putImageData(imageData, 0, 0)

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

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:

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

Fast bilinear interpolation on old iOS devices

I've got the following code to do a biliner interpolation from a matrix of 2D vectors, each cell has x and y values of the vector, and the function receives k and l indices telling the bottom-left nearest position in the matrix
// p[1] returns the interpolated values
// fieldLinePointsVerts the raw data array of fieldNumHorizontalPoints x fieldNumVerticalPoints
// only fieldNumHorizontalPoints matters to determine the index to access the raw data
// k and l horizontal and vertical indices of the point just bellow p[0] in the raw data
void interpolate( vertex2d* p, vertex2d* fieldLinePointsVerts, int fieldNumHorizontalPoints, int k, int l ) {
int index = (l * fieldNumHorizontalPoints + k) * 2;
vertex2d p11;
p11.x = fieldLinePointsVerts[index].x;
p11.y = fieldLinePointsVerts[index].y;
vertex2d q11;
q11.x = fieldLinePointsVerts[index+1].x;
q11.y = fieldLinePointsVerts[index+1].y;
index = (l * fieldNumHorizontalPoints + k + 1) * 2;
vertex2d q21;
q21.x = fieldLinePointsVerts[index+1].x;
q21.y = fieldLinePointsVerts[index+1].y;
index = ( (l + 1) * fieldNumHorizontalPoints + k) * 2;
vertex2d q12;
q12.x = fieldLinePointsVerts[index+1].x;
q12.y = fieldLinePointsVerts[index+1].y;
index = ( (l + 1) * fieldNumHorizontalPoints + k + 1 ) * 2;
vertex2d p22;
p22.x = fieldLinePointsVerts[index].x;
p22.y = fieldLinePointsVerts[index].y;
vertex2d q22;
q22.x = fieldLinePointsVerts[index+1].x;
q22.y = fieldLinePointsVerts[index+1].y;
float fx = 1.0 / (p22.x - p11.x);
float fx1 = (p22.x - p[0].x) * fx;
float fx2 = (p[0].x - p11.x) * fx;
vertex2d r1;
r1.x = fx1 * q11.x + fx2 * q21.x;
r1.y = fx1 * q11.y + fx2 * q21.y;
vertex2d r2;
r2.x = fx1 * q12.x + fx2 * q22.x;
r2.y = fx1 * q12.y + fx2 * q22.y;
float fy = 1.0 / (p22.y - p11.y);
float fy1 = (p22.y - p[0].y) * fy;
float fy2 = (p[0].y - p11.y) * fy;
p[1].x = fy1 * r1.x + fy2 * r2.x;
p[1].y = fy1 * r1.y + fy2 * r2.y;
}
Currently this code needs to be run every single frame in old iOS devices, say devices with arm6 processors
I've taken the numeric sub-indices from the wikipedia's equations http://en.wikipedia.org/wiki/Bilinear_interpolation
I'd accreciate any comments on optimization for performance, even plain asm code
This code should not be causing your slowdown if it's only run once per frame. However, if it's run multiple times per frame, it easily could be.
I'd run your app with a profiler to see where the true performance problem lies.
There is some room for optimization here: a) Certain index calculations could be factored out and re-used in subsequent calculations), b) You could dereference your fieldLinePointsVerts array to a pointer once and re-use that, instead of indexing it twice per index...
but in general those things won't help a great deal, unless this function is being called many, many times per frame. In which case every little thing will help.

Resources