Translate VBA map into dart/flutter map - vba

I am trying to translate VBA to dart and am having trouble. I believe it has to do with how I implement my xxMap and wMap. How do I make maps with keys that have two integers, then how do I use it? I have been trying to fix this for a while and just cannot figure it out. I would greatly appreciate any help that anyone can offer me! I truly hope you all have a good day!
Here is the VBA code:
Public Function CBND(X As Double, y As Double, rho As Double) As Double
Dim i As Integer, ISs As Integer, LG As Integer, NG As Integer
Dim XX(10, 3) As Double, W(10, 3) As Double
Dim h As Double, k As Double, hk As Double, hs As Double, BVN As Double, Ass As Double, asr As Double, sn As Double
Dim A As Double, b As Double, bs As Double, c As Double, d As Double
Dim xs As Double, rs As Double
W(1, 1) = 0.17132449237917
XX(1, 1) = -0.932469514203152
W(2, 1) = 0.360761573048138
XX(2, 1) = -0.661209386466265
W(3, 1) = 0.46791393457269
XX(3, 1) = -0.238619186083197
W(1, 2) = 4.71753363865118E-02
XX(1, 2) = -0.981560634246719
W(2, 2) = 0.106939325995318
XX(2, 2) = -0.904117256370475
W(3, 2) = 0.160078328543346
XX(3, 2) = -0.769902674194305
W(4, 2) = 0.203167426723066
XX(4, 2) = -0.587317954286617
W(5, 2) = 0.233492536538355
XX(5, 2) = -0.36783149899818
W(6, 2) = 0.249147045813403
XX(6, 2) = -0.125233408511469
W(1, 3) = 1.76140071391521E-02
XX(1, 3) = -0.993128599185095
W(2, 3) = 4.06014298003869E-02
XX(2, 3) = -0.963971927277914
W(3, 3) = 6.26720483341091E-02
XX(3, 3) = -0.912234428251326
W(4, 3) = 8.32767415767048E-02
XX(4, 3) = -0.839116971822219
W(5, 3) = 0.10193011981724
XX(5, 3) = -0.746331906460151
W(6, 3) = 0.118194531961518
XX(6, 3) = -0.636053680726515
W(7, 3) = 0.131688638449177
XX(7, 3) = -0.510867001950827
W(8, 3) = 0.142096109318382
XX(8, 3) = -0.37370608871542
W(9, 3) = 0.149172986472604
XX(9, 3) = -0.227785851141645
W(10, 3) = 0.152753387130726
XX(10, 3) = -7.65265211334973E-02
If Abs(rho) < 0.3 Then
NG = 1
LG = 3
ElseIf Abs(rho) < 0.75 Then
NG = 2
LG = 6
Else
NG = 3
LG = 10
End If
h = -X
k = -y
hk = h * k
BVN = 0
If Abs(rho) < 0.925 Then
If Abs(rho) > 0 Then
hs = (h * h + k * k) / 2
asr = ArcSin(rho)
For i = 1 To LG
For ISs = -1 To 1 Step 2
sn = Sin(asr * (ISs * XX(i, NG) + 1) / 2)
BVN = BVN + W(i, NG) * Exp((sn * hk - hs) / (1 - sn * sn))
Next ISs
Next i
BVN = BVN * asr / (4 * Pi)
End If
BVN = BVN + CND(-h) * CND(-k)
Else
If rho < 0 Then
k = -k
hk = -hk
End If
If Abs(rho) < 1 Then
Ass = (1 - rho) * (1 + rho)
A = Sqr(Ass)
bs = (h - k) ^ 2
c = (4 - hk) / 8
d = (12 - hk) / 16
asr = -(bs / Ass + hk) / 2
If asr > -100 Then BVN = A * Exp(asr) * (1 - c * (bs - Ass) * (1 - d * bs / 5) / 3 + c * d * Ass * Ass / 5)
If -hk < 100 Then
b = Sqr(bs)
BVN = BVN - Exp(-hk / 2) * Sqr(2 * Pi) * CND(-b / A) * b * (1 - c * bs * (1 - d * bs / 5) / 3)
End If
A = A / 2
For i = 1 To LG
For ISs = -1 To 1 Step 2
xs = (A * (ISs * XX(i, NG) + 1)) ^ 2
rs = Sqr(1 - xs)
asr = -(bs / xs + hk) / 2
If asr > -100 Then
BVN = BVN + A * W(i, NG) * Exp(asr) * (Exp(-hk * (1 - rs) / (2 * (1 + rs))) / rs - (1 + c * xs * (1 + d * xs)))
End If
Next ISs
Next i
BVN = -BVN / (2 * Pi)
End If
If rho > 0 Then
BVN = BVN + CND(-Max(h, k))
Else
BVN = -BVN
If k > h Then BVN = BVN + CND(k) - CND(h)
End If
End If
CBND = BVN
End Function
Here is my dart/flutter translation:
import 'dart:math';
double cbnd (double X, double y, double rho) {
int i;
int iss;
int lg;
int ng;
double h;
double k;
double hk;
double hs;
double bvn;
double ass;
double asr;
double sn;
double a;
double b;
double bs;
double c;
double d;
double xs;
double rs;
Map<List<int>, double> wMap = {
[1, 1] : 0.17132449237917,
[2, 1] : 0.360761573048138,
[3, 1] : 0.46791393457269,
[1, 2] : 0.0471753363865118,
[2, 2] : 0.106939325995318,
[3, 2] : 0.160078328543346,
[4, 2] : 0.203167426723066,
[5, 2] : 0.233492536538355,
[6, 2] : 0.249147045813403,
[1, 3] : 0.0176140071391521,
[2, 3] : 0.0406014298003869,
[3, 3] : 0.0626720483341091,
[4, 3] : 0.0832767415767048,
[5, 3] : 0.10193011981724,
[6, 3] : 0.118194531961518,
[7, 3] : 0.131688638449177,
[8, 3] : 0.142096109318382,
[9, 3] : 0.149172986472604,
[10, 3] : 0.152753387130726,
};
Map<List<int>, double> xxMap = {
[1, 1] : -0.932469514203152,
[2, 1] : -0.661209386466265,
[3, 1] : -0.238619186083197,
[1, 2] : -0.981560634246719,
[2, 2] : -0.904117256370475,
[3, 2] : -0.769902674194305,
[4, 2] : -0.587317954286617,
[5, 2] : -0.36783149899818,
[6, 2] : -0.125233408511469,
[1, 3] : -0.993128599185095,
[2, 3] : -0.963971927277914,
[3, 3] : -0.912234428251326,
[4, 3] : -0.839116971822219,
[5, 3] : -0.746331906460151,
[6, 3] : -0.636053680726515,
[7, 3] : -0.510867001950827,
[8, 3] : -0.37370608871542,
[9, 3] : -0.227785851141645,
[10, 3] : -0.0765265211334973,
};
if (rho.abs() < 0.3) {
ng = 1;
lg = 3;
}
else if (rho.abs() < 0.75) {
ng = 2;
lg = 6;
}
else {
ng = 3;
lg = 10;
}
h = -X;
k = -y;
hk = h * k;
bvn = 0;
if (rho.abs() < 0.925) {
if (rho.abs() > 0) {
hs = (h * h + k * k) / 2;
asr = arcSin(rho);
for(i = 1; i < lg; i++) {
for(iss = -1; iss < 1; iss+=2) {
sn = sin(asr * (iss * xxMap[[i,ng]] + 1) / 2);
bvn = bvn + wMap[[i,ng]] * exp((sn * hk - hs) / (1 - sn * sn));
}
}
bvn = bvn * asr / (4 * pi);
}
bvn = bvn + cnd(-h) * cnd(-k);
}
else{
if (rho < 0) {
k = -k;
hk = -hk;
}
if (rho.abs() < 1) {
ass = (1 - rho) * (1 + rho);
a = sqrt(ass);
bs = pow((h - k), 2);
c = (4 - hk) / 8;
d = (12 - hk) / 16;
asr = -(bs / ass + hk) / 2;
if (asr > -100) {
bvn = a * exp(asr) * (1 - c * (bs - ass)
* (1 - d * bs / 5) / 3 + c * d * ass * ass / 5);
if (-hk < 100) {
b = sqrt(bs);
bvn = bvn - exp(-hk / 2) * sqrt(2 * pi) * cnd(-b / a)
* b * (1 - c * bs * (1 - d * bs / 5) / 3);
}
a = a / 2;
for(i = 1; i < lg; i++) {
for (iss = -1; iss < 1; iss+=2) {
xs = pow(a * (iss * xxMap[{i, ng}] +1), 2);
rs = sqrt(1 - xs);
asr = -(bs / xs + hk) / 2;
if (asr > -100) {
bvn = bvn + a * wMap[{i, ng}] * exp(asr)
* (exp(-hk * (1 - rs) / (2 * (1 + rs))) / rs
- (1 + c * xs * (1 + d * xs)));
}
}
}
bvn = - bvn / (2 * pi);
}
if (rho > 0) {
bvn = bvn + cnd(-max(h, k));
}
else {
bvn = -bvn;
if (k > h) {
bvn = bvn + cnd(k) - cnd(h);
}
}
}
}
print(bvn);
return bvn;
}
Here is the error code:
Performing hot restart...
Syncing files to device Android SDK built for x86...
Restarted application in 135ms.
I/flutter ( 7281): 0.6033458857722407
I/flutter ( 7281): 0.396061477681382
I/flutter ( 7281): 9588.900336837181
I/flutter ( 7281): 0.6066215038705733
I/flutter ( 7281): 0.39322784023367435
I/flutter ( 7281): 21.675664402433934
I/flutter ( 7281): 0.5567942331117398
I/flutter ( 7281): 0.43911123505550037
I/flutter ( 7281): 11.019478064121111
I/flutter ( 7281): 0.6067721597663256
I/flutter ( 7281): 0.3933784961294267
I/flutter ( 7281): 0.2265553776778987
I/flutter ( 7281): 0.5708243206704915
I/flutter ( 7281): 0.4261760665459637
I/flutter ( 7281): 0.1594404921802129
I/flutter ( 7281): 0.5331974688940583
I/flutter ( 7281): 0.4606874160295979
I/flutter ( 7281): 207.2825189948513
I/flutter ( 7281): 0.9045568943023813
E/flutter ( 7281): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: NoSuchMethodError: The method '_mulFromInteger' was called on null.
E/flutter ( 7281): Receiver: null
E/flutter ( 7281): Tried calling: _mulFromInteger(-1)
E/flutter ( 7281): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
E/flutter ( 7281): #1 int.* (dart:core-patch/integers.dart:16:38)
E/flutter ( 7281): #2 cbnd (package:flutter_apptest/main.dart:280:31)
E/flutter ( 7281): #3 ksi (package:flutter_apptest/main.dart:92:47)
E/flutter ( 7281): #4 bsAmericanCallApprox2002 (package:flutter_apptest/main.dart:57:67)
E/flutter ( 7281): #5 bsAmericanApprox2002 (package:flutter_apptest/main.dart:12:13)
E/flutter ( 7281): #6 main (package:flutter_apptest/main.dart:4:18)
E/flutter ( 7281): #7 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:231:25)
E/flutter ( 7281): #8 _rootRun (dart:async/zone.dart:1190:13)
E/flutter ( 7281): #9 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter ( 7281): #10 _runZoned (dart:async/zone.dart:1630:10)
E/flutter ( 7281): #11 runZonedGuarded (dart:async/zone.dart:1618:12)
E/flutter ( 7281): #12 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:223:5)
E/flutter ( 7281): #13 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
E/flutter ( 7281): #14 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
E/flutter ( 7281):

You have typos in these two lines:
xs = pow(a * (iss * xxMap[{i, ng}] +1), 2);
...
bvn = bvn + a * wMap[{i, ng}] * exp(asr)
You are passing in a Set as the key when you meant to pass a List.
Simply change the {} to [] like so:
xs = pow(a * (iss * xxMap[[i, ng]] +1), 2);
...
bvn = bvn + a * wMap[[i, ng]] * exp(asr)

Related

Conversion ECEF XYZ to LLH (LAT/LONG/HEIGHT) and translation back - not accurate / possible error in IronPython script

I've modeled a 3D earth with gridpoints, as below:
The points are represented in 3D space as XYZ coordinates.
I then convert XYZ to Lat/Long/Height(elevation) based on the script I took from here:
JSFiddle
For some reason I got really strange results when trying to find XYZ of LLH not from my set, so I tried to verify the initial script by converting XYZ to LLH and then the same LLH back to XYZ to see if I get the same coordinate.
Instead, the resulting coordinate is some XYZ on earth, unrelated to the original XYZ position.
XYZ to LLH script:
Source: JSFiddle
def xyzllh(x,y,z):
""" xyz vector to lat,lon,height
output:
llhvec[3] with components
flat geodetic latitude in deg
flon longitude in deg
altkm altitude in km
"""
dtr = math.pi/180.0
rrnrm = [0.0] * 3
llhvec = [0.0] * 3
geodGBL()
esq = EARTH_Esq
rp = math.sqrt( x*x + y*y + z*z )
flatgc = math.asin( z / rp )/dtr
testval= abs(x) + abs(y)
if ( testval < 1.0e-10):
flon = 0.0
else:
flon = math.atan2( y,x )/dtr
if (flon < 0.0 ):
flon = flon + 360.0
p = math.sqrt( x*x + y*y )
# on pole special case
if ( p < 1.0e-10 ):
flat = 90.0
if ( z < 0.0 ):
flat = -90.0
altkm = rp - rearth(flat)
llhvec[0] = flat
llhvec[1] = flon
llhvec[2] = altkm
return llhvec
# first iteration, use flatgc to get altitude
# and alt needed to convert gc to gd lat.
rnow = rearth(flatgc)
altkm = rp - rnow
flat = gc2gd(flatgc,altkm)
rrnrm = radcur(flat)
rn = rrnrm[1]
for x in range(5):
slat = math.sin(dtr*flat)
tangd = ( z + rn*esq*slat ) / p
flatn = math.atan(tangd)/dtr
dlat = flatn - flat
flat = flatn
clat = math.cos( dtr*flat )
rrnrm = radcur(flat)
rn = rrnrm[1]
altkm = (p/clat) - rn
if ( abs(dlat) < 1.0e-12 ):
break
llhvec[0] = flat
llhvec[1] = flon
llhvec[2] = altkm
return llhvec
# globals
EARTH_A = 0
EARTH_B = 0
EARTH_F = 0
EARTH_Ecc = 0
EARTH_Esq = 0
# starting function do_llhxyz()
CallCount = 0
llh = [0.0] * 3
dtr = math.pi/180
CallCount = CallCount + 1
sans = " \n"
llh = xyzllh(x,y,z)
latitude = llh[0]
longitude= llh[1]
hkm = llh[2]
height = 1000.0 * hkm
latitude = fformat(latitude,5)
longitude = fformat(longitude,5)
height = fformat(height,1)
sans = sans +"Latitude,Longitude, Height (ellipsoidal) from ECEF\n"
sans = sans + "\n"
sans = sans +"Latitude : " + str(latitude) + " deg N\n"
sans = sans +"Longitude : " + str(longitude - 180) + " deg E\n"
sans = sans +"Height : " + str(height) + " m\n"
lats = []
longs = []
heights = []
lats.append(str(latitude))
longs.append(str(longitude - 180))
heights.append(str(height))
And this is the LLH to XYZ script:
Source: www.mathworks.com
a = 6378137
t = 8.1819190842622e-2
# (prime vertical radius of curvature)
N = a / math.sqrt(1 - (t*t) * (math.sin(lat)*math.sin(lat)))
x = []
y = []
z = []
# results:
x.append( ((N+height) * math.cos(lat) * math.cos(long))/1000 )
y.append( ((N+height) * math.cos(lat) * math.sin(long))/1000 )
z.append( (((1-t*t) * N + height) * math.sin(lat))/1000 )
Anyone know what I'm doing wrong here?
Thanks!

Accurately calculate moon phases

For a new project I like to calculate the moon phases. So far I haven't seen any code that does that. I don't want to rely on online-services for this.
I have tried some functions, but they are not 100% reliable. Functions I have tried:
NSInteger r = iYear % 100;
r %= 19;
if (r>9){ r -= 19;}
r = ((r * 11) % 30) + iMonth + iDay;
if (iMonth<3){r += 2;}
r -= ((iYear<2000) ? 4 : 8.3);
r = floor(r+0.5);
other one:
float n = floor(12.37 * (iYear -1900 + ((1.0 * iMonth - 0.5)/12.0)));
float RAD = 3.14159265/180.0;
float t = n / 1236.85;
float t2 = t * t;
float as = 359.2242 + 29.105356 * n;
float am = 306.0253 + 385.816918 * n + 0.010730 * t2;
float xtra = 0.75933 + 1.53058868 * n + ((1.178e-4) - (1.55e-7) * t) * t2;
xtra = xtra + (0.1734 - 3.93e-4 * t) * sin(RAD * as) - 0.4068 * sin(RAD * am);
float i = (xtra > 0.0 ? floor(xtra) : ceil(xtra - 1.0));
float j1 = [self julday:iYear iMonth:iMonth iDay:iDay];
float jd = (2415020 + 28 * n) + i;
jd = fmodf((j1-jd + 30), 30);
and last one
NSInteger thisJD = [self julday:iYear iMonth:iMonth iDay:iDay];
float degToRad = 3.14159265 / 180;
float K0, T, T2, T3, J0, F0, M0, M1, B1, oldJ = 0.0;
K0 = floor((iYear-1900)*12.3685);
T = (iYear-1899.5) / 100;
T2 = T*T; T3 = T*T*T;
J0 = 2415020 + 29*K0;
F0 = 0.0001178*T2 - 0.000000155*T3 + (0.75933 + 0.53058868*K0) - (0.000837*T + 0.000335*T2);
M0 = 360*[self getFrac:((K0*0.08084821133)) + 359.2242 - 0.0000333*T2 - 0.00000347*T3];
M1 = 360*[self getFrac:((K0*0.07171366128)) + 306.0253 + 0.0107306*T2 + 0.00001236*T3];
B1 = 360*[self getFrac:((K0*0.08519585128)) + 21.2964 - (0.0016528*T2) - (0.00000239*T3)];
NSInteger phase = 0;
NSInteger jday = 0;
while (jday < thisJD) {
float F = F0 + 1.530588*phase;
float M5 = (M0 + phase*29.10535608)*degToRad;
float M6 = (M1 + phase*385.81691806)*degToRad;
float B6 = (B1 + phase*390.67050646)*degToRad;
F -= 0.4068*sin(M6) + (0.1734 - 0.000393*T)*sin(M5);
F += 0.0161*sin(2*M6) + 0.0104*sin(2*B6);
F -= 0.0074*sin(M5 - M6) - 0.0051*sin(M5 + M6);
F += 0.0021*sin(2*M5) + 0.0010*sin(2*B6-M6);
F += 0.5 / 1440;
oldJ=jday;
jday = J0 + 28*phase + floor(F);
phase++;
}
float jd = fmodf((thisJD-oldJ), 30);
All are working more and less, but none is really giving the correct dates of full moon for 2017 and 2018.
Does anyone have a function that will calculate the moon phases correctly - also based on time zone?
EDIT:
I only want the function for the Moonphases. SwiftAA offers a lot more and only produces not needed overhead in the app.

Maya-like camera implementation

I am working on Maya-like camera implementation, and I've done track and dolly functions correctly but I just cannot implement tumble.
I am working in PhiloGL engine (WebGL base), so I would really appreciate some help with code in this engine.
I've looked at how Maya's camera actually work, but I cannot find out. Here is my code so-far
if(mode == "rot")
{
var angleX = diffx / 150;
var angleY = diffy / 150;
//var angleZ = sign * Math.sqrt((diffx * diffx)+(diffy * diffy)) / 150;
e.stop();
//axe Z
//camera.position.x = x * Math.cos(angleX) - y * Math.sin(angleX);
//camera.position.y = x * Math.sin(angleX) + y * Math.cos(angleX);
//axe X
//camera.position.y = y * Math.cos(angleY) - z * Math.sin(angleY);
//camera.position.z = y * Math.sin(angleY) + z * Math.cos(angleY);
//camera.update();
//axe Y
camera.position.z = z * Math.cos(angleX) - x * Math.sin(angleX);
camera.position.x = z * Math.sin(angleX) + x * Math.cos(angleX);
camera.update();
position.x = e.x;
position.y = e.y;
position.z = e.z;
}
This isn't working nor do I know what am I doing wrong.
Any clues?
I use this in inka3d (www.inka3d.com) but it does not depend on inka3d. The output is a 4x4 matrix. Can you make use of that?
// turntable like camera, y is up-vector
// tx, ty and tz are camera target position
// rx, ry and rz are camera rotation angles (rad)
// di is camera distance from target
// fr is an array where the resulting view matrix is written into (16 values, row major)
control.cameraY = function(tx, ty, tz, rx, ry, rz, di, fr)
{
var a = rx * 0.5;
var b = ry * 0.5;
var c = rz * 0.5;
var d = Math.cos(a);
var e = Math.sin(a);
var f = Math.cos(b);
var g = Math.sin(b);
var h = Math.cos(c);
var i = Math.sin(c);
var j = f * e * h + g * d * i;
var k = f * -e * i + g * d * h;
var l = f * d * i - g * e * h;
var m = f * d * h - g * -e * i;
var n = j * j;
var o = k * k;
var p = l * l;
var q = m * m;
var r = j * k;
var s = k * l;
var t = j * l;
var u = m * j;
var v = m * k;
var w = m * l;
var x = q + n - o - p;
var y = (r + w) * 2.0;
var z = (t - v) * 2.0;
var A = (r - w) * 2.0;
var B = q - n + o - p;
var C = (s + u) * 2.0;
var D = (t + v) * 2.0;
var E = (s - u) * 2.0;
var F = q - n - o + p;
var G = di;
var H = -(tx + D * G);
var I = -(ty + E * G);
var J = -(tz + F * G);
fr[0] = x;
fr[1] = A;
fr[2] = D;
fr[3] = 0.0;
fr[4] = y;
fr[5] = B;
fr[6] = E;
fr[7] = 0.0;
fr[8] = z;
fr[9] = C;
fr[10] = F;
fr[11] = 0.0;
fr[12] = x * H + y * I + z * J;
fr[13] = A * H + B * I + C * J;
fr[14] = D * H + E * I + F * J;
fr[15] = 1.0;
};

missing value where TRUE/FALSE needed

I'm working on pairs trading data and following function should give total.profit with value "k".
optimal.k = function (k) {
u = m + k * s
l = m - k * s
profit = 0
profit = 0
total.profit = 0
i = 1
p = 0.001
while ( i <= length(r) ) {
if ( r[i] >= u ) {
buy.unit = 1/East$Close[i]
sell.unit = 1/South$Close[i]
if ( i == length(r) ) {
buy.price = buy.unit * East$Close[i]
sell.price = sell.unit * South$Close[i]
profit = sell.price - buy.price
costs = (sell.price + buy.price) * p
total.profit = total.profit + profit - costs
break
}
while ( r[i] > m ) { #################################### here
i = i + 1
}
buy.price = buy.unit * East$Close[i]
sell.price = sell.unit * South$Close[i]
profit = sell.price - buy.price
costs = (sell.price + buy.price) * p
total.profit = total.profit + profit - costs
}
if ( r[i] <= l ) {
buy.unit = 1/South$Close[i]
sell.unit = 1/East$Close[i]
if ( i == length(r) ) {
buy.price = buy.unit * South$Close[i]
sell.price = sell.unit * East$Close[i]
profit = sell.price - buy.price
costs = (sell.price + buy.price) * p
total.profit = total.profit + profit - costs
break
}
while ( r[i] < m ) {
i = i + 1
}
buy.price = buy.unit * East$Close[i]
sell.price = sell.unit * South$Close[i]
profit = sell.price - buy.price
costs = (sell.price + buy.price) * p
total.profit = total.profit + profit - costs
}
if ( i == length(r) ) stop
i = i + 1
}
print(total.profit)
}
If I run the function, I get this error message.
optimal.k(1)
Error in while (r[i] > m) { : missing value where TRUE/FALSE needed
I don't get it why (r[i] > m) is NA
Does anyone know why it occurs?

Return CATransform3D to map quadrilateral to quadrilateral

I'm trying to derive a CATransform3D that will map a quad with 4 corner points to another quad with 4 new corner points. I've spent a little bit of time researching this and it seems the steps involve converting the original Quad to a Square, and then converting that Square to the new Quad. My methods look like this (code borrowed from here):
- (CATransform3D)quadFromSquare_x0:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 {
float dx1 = x1 - x2, dy1 = y1 - y2;
float dx2 = x3 - x2, dy2 = y3 - y2;
float sx = x0 - x1 + x2 - x3;
float sy = y0 - y1 + y2 - y3;
float g = (sx * dy2 - dx2 * sy) / (dx1 * dy2 - dx2 * dy1);
float h = (dx1 * sy - sx * dy1) / (dx1 * dy2 - dx2 * dy1);
float a = x1 - x0 + g * x1;
float b = x3 - x0 + h * x3;
float c = x0;
float d = y1 - y0 + g * y1;
float e = y3 - y0 + h * y3;
float f = y0;
CATransform3D mat;
mat.m11 = a;
mat.m12 = b;
mat.m13 = 0;
mat.m14 = c;
mat.m21 = d;
mat.m22 = e;
mat.m23 = 0;
mat.m24 = f;
mat.m31 = 0;
mat.m32 = 0;
mat.m33 = 1;
mat.m34 = 0;
mat.m41 = g;
mat.m42 = h;
mat.m43 = 0;
mat.m44 = 1;
return mat;
}
- (CATransform3D)squareFromQuad_x0:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 {
CATransform3D mat = [self quadFromSquare_x0:x0 y0:y0 x1:x1 y1:y1 x2:x2 y2:y2 x3:x3 y3:y3];
// invert through adjoint
float a = mat.m11, d = mat.m21, /* ignore */ g = mat.m41;
float b = mat.m12, e = mat.m22, /* 3rd col*/ h = mat.m42;
/* ignore 3rd row */
float c = mat.m14, f = mat.m24;
float A = e - f * h;
float B = c * h - b;
float C = b * f - c * e;
float D = f * g - d;
float E = a - c * g;
float F = c * d - a * f;
float G = d * h - e * g;
float H = b * g - a * h;
float I = a * e - b * d;
// Probably unnecessary since 'I' is also scaled by the determinant,
// and 'I' scales the homogeneous coordinate, which, in turn,
// scales the X,Y coordinates.
// Determinant = a * (e - f * h) + b * (f * g - d) + c * (d * h - e * g);
float idet = 1.0f / (a * A + b * D + c * G);
mat.m11 = A * idet; mat.m21 = D * idet; mat.m31 = 0; mat.m41 = G * idet;
mat.m12 = B * idet; mat.m22 = E * idet; mat.m32 = 0; mat.m42 = H * idet;
mat.m13 = 0 ; mat.m23 = 0 ; mat.m33 = 1; mat.m43 = 0 ;
mat.m14 = C * idet; mat.m24 = F * idet; mat.m34 = 0; mat.m44 = I * idet;
return mat;
}
After calculating both matrices, multiplying them together, and assigning to the view in question, I end up with a transformed view, but it is wildly incorrect. In fact, it seems to be sheared like a parallelogram no matter what I do. What am I missing?
UPDATE 2/1/12
It seems the reason I'm running into issues may be that I need to accommodate for FOV and focal length into the model view matrix (which is the only matrix I can alter directly in Quartz.) I'm not having any luck finding documentation online on how to calculate the proper matrix, though.
I was able to achieve this by porting and combining the quad warping and homography code from these two URLs:
http://forum.openframeworks.cc/index.php/topic,509.30.html
http://forum.openframeworks.cc/index.php?topic=3121.15
UPDATE: I've open sourced a small class that does this: https://github.com/dominikhofmann/DHWarpView