It is possible to get the Block the Player actually is looking at.
p.getTargetBlock()
But is there a way to get the side of the block that the player is looking at?
(top, down, north, south, east, west side of the block)
I haven't found a function that will do that. Does it give me something, that I can use to find this side?
I have implemented a Utility method for achieving this given the AxisAlignedBB (NMS) of the Block the player is targeting. This block can be obtained by Player#getTargetBlock() as mentioned in the question or with a custom raycast algorithm.
public static BlockFace blockFaceCollide(Vector startLocation, Vector direction, AxisAlignedBB objectBoundry){
double constant = Double.MAX_VALUE;
BlockFace blockFace = null;
double directionX = direction.getX();
double directionY = direction.getY();
double directionZ = direction.getZ();
if(directionY > 0){
double b = objectBoundry.b - startLocation.getY();
double tempConstant = b / directionY;
if(tempConstant > 0 && tempConstant < constant){
double xAtCollide = tempConstant * directionX + startLocation.getX();
double zAtCollide = tempConstant * directionZ + startLocation.getZ();
if (between(xAtCollide, objectBoundry.a, objectBoundry.d, 0)
&& between(zAtCollide, objectBoundry.c, objectBoundry.f, 0)) {
constant = tempConstant;
blockFace = BlockFace.DOWN;
}
}
}
else {
double e = objectBoundry.e - startLocation.getY();
double tempConstant = e / directionY;
if (tempConstant > 0 && tempConstant < constant) {
double xAtCollide = tempConstant * directionX + startLocation.getX();
double zAtCollide = tempConstant * directionZ + startLocation.getZ();
if (between(xAtCollide, objectBoundry.a, objectBoundry.d, 0)
&& between(zAtCollide, objectBoundry.c, objectBoundry.f, 0)) {
constant = tempConstant;
blockFace = BlockFace.UP;
}
}
}
if(directionX < 0) {
double d = objectBoundry.d - startLocation.getX();
double tempConstant = d / directionX;
if (tempConstant > 0 && tempConstant < constant) {
double yAtCollide = tempConstant * directionY + startLocation.getY();
double zAtCollide = tempConstant * directionZ + startLocation.getZ();
if (between(yAtCollide, objectBoundry.b, objectBoundry.e, 0)
&& between(zAtCollide, objectBoundry.c, objectBoundry.f, 0)) {
constant = tempConstant;
blockFace = BlockFace.EAST;
}
}
}
else {
double a = objectBoundry.a - startLocation.getX();
double tempConstant = a / directionX;
if (tempConstant > 0 && tempConstant < constant) {
double yAtCollide = tempConstant * directionY + startLocation.getY();
double zAtCollide = tempConstant * directionZ + startLocation.getZ();
if (between(yAtCollide, objectBoundry.b, objectBoundry.e, 0)
&& between(zAtCollide, objectBoundry.c, objectBoundry.f, 0)) {
constant = tempConstant;
blockFace = BlockFace.WEST;
}
}
}
if(directionZ > 0) {
double c = objectBoundry.c - startLocation.getZ();
double tempConstant = c / directionZ;
if(tempConstant > 0 && tempConstant < constant) {
double yAtCollide = tempConstant * directionY + startLocation.getY();
double xAtCollide = tempConstant * directionX + startLocation.getX();
if (between(yAtCollide, objectBoundry.b, objectBoundry.e, 0)
&& between(xAtCollide, objectBoundry.a, objectBoundry.d, 0)) {
blockFace = BlockFace.NORTH;
}
}
}
else {
double f = objectBoundry.f - startLocation.getZ();
double tempConstant = f / directionZ;
if(tempConstant < constant) {
double yAtCollide = tempConstant * directionY + startLocation.getY();
double xAtCollide = tempConstant * directionX + startLocation.getX();
if (between(yAtCollide, objectBoundry.b, objectBoundry.e, 0)
&& between(xAtCollide, objectBoundry.a, objectBoundry.d, 0)) {
blockFace = BlockFace.SOUTH;
}
}
}
return blockFace;
}
public static boolean between(double num, double a, double b, double EOF) {
if (a <= b)
return num + EOF >= a && num - EOF <= b;
return num + EOF >= b && num - EOF <= a;
}
I don't think there is way to get the block they are looking at, however you can get the block face that they click by using PlayerInteractEvent and its getBlockFace() method.
EDIT: Check out this thread on the bukkit forums.
EDIT 2: Or as mentioned in this thread, you can try putting this in a PlayerMoveEvent:
List<Block> blocks = event.getPlayer().getLastTwoTargetBlocks(null, 10);
if (blocks.size() > 1)
face = blocks.get(1).getFace(blocks.get(0));
Related
I'm translating Python's version of 'page_dewarper' (https://mzucker.github.io/2016/08/15/page-dewarping.html) into C++. I'm going to use dlib, which is a fantastic tool, that helped me in a few optimization problems before. In line 748 of Github repo (https://github.com/mzucker/page_dewarp/blob/master/page_dewarp.py) Matt uses optimize function from Scipy, to find the minimal distance between two vectors. I think, my C++ equivalent should be solve_least_squares_lm() or solve_least_squares(). I'll give a concrete example to analyze.
My data:
a) dstpoints is a vector with OpenCV points - std::vector<cv::Point2f> (I have 162 points in this example, they are not changing),
b) ppts is also std::vector<cv::Point2f> and the same size as dstpoints.
std::vector<cv::Point2f> ppts = project_keypoints(params, input);
It is dependent on:
- dlib::column_vector 'input' is 2*162=324 long and is not changing,
- dlib::column_vector 'params' is 189 long and its values should be changed to get the minimal value of variable 'suma', something like this:
double suma = 0.0;
for (int i=0; i<dstpoints_size; i++)
{
suma += pow(dstpoints[i].x - ppts[i].x, 2);
suma += pow(dstpoints[i].y - ppts[i].y, 2);
}
I'm looking for 'params' vector that will give me the smallest value of 'suma' variable. Least squares algorithm seems to be a good option to solve it: http://dlib.net/dlib/optimization/optimization_least_squares_abstract.h.html#solve_least_squares, but I don't know if it is good for my case.
I think, my problem is that for every different 'params' vector I get different 'ppts' vector, not only single value, and I don't know if solve_least_squares function can match my example.
I must calculate residual for every point. I think, my 'list' from aforementioned link should be something like this:
(ppts[i].x - dstpoints[i].x, ppts[i].y - dstpoints[i].y, ppts[i+1].x - dstpoints[i+1].x, ppts[i+1].y - dstpoints[i+1].y, etc.)
, where 'ppts' vector depends on 'params' vector and then this problem can be solved with least squares algorithm. I don't know how to create data_samples with these assumptions, because it requires dlib::input_vector for every sample, as it is shown in example: http://dlib.net/least_squares_ex.cpp.html.
Am I thinking right?
I'm doing the same thing this days. My solution is writing a Powell Class by myself. It works, but really slowly. The program takes 2 minutes in dewarping linguistics_thesis.jpg.
I don't know what cause the program running so slowly. Maybe because of the algorithm or the code has some extra loop. I'm a Chinese student and my school only have java lessons. So it is normal if you find some extra codes in my codes.
Here is my Powell class.
using namespace std;
using namespace cv;
class MyPowell
{
public:
vector<vector<double>> xi;
vector<double> pcom;
vector<double> xicom;
vector<Point2d> dstpoints;
vector<double> myparams;
vector<double> params;
vector<Point> keypoint_index;
Point2d dst_br;
Point2d dims;
int N;
int itmax;
int ncom;
int iter;
double fret, ftol;
int usingAorB;
MyPowell(vector<Point2d> &dstpoints, vector<double> ¶ms, vector<Point> &keypoint_index);
MyPowell(Point2d &dst_br, vector<double> ¶ms, Point2d & dims);
MyPowell();
double obj(vector<double> ¶ms);
void powell(vector<double> &p, vector<vector<double>> &xi, double ftol, double &fret);
double sign(double a);// , double b);
double sqr(double a);
void linmin(vector<double> &p, vector<double> &xit, int n, double &fret);
void mnbrak(double & ax, double & bx, double & cx,
double & fa, double & fb, double & fc);
double f1dim(double x);
double brent(double ax, double bx, double cx, double & xmin, double tol);
vector<double> usePowell();
void erase(vector<double>& pbar, vector<double> &prr, vector<double> &pr);
};
#include"Powell.h"
MyPowell::MyPowell(vector<Point2d> &dstpoints, vector<double>& params, vector<Point> &keypoint_index)
{
this->dstpoints = dstpoints;
this->myparams = params;
this->keypoint_index = keypoint_index;
N = params.size();
itmax = N * N;
usingAorB = 1;
}
MyPowell::MyPowell(Point2d & dst_br, vector<double>& params, Point2d & dims)
{
this->dst_br = dst_br;
this->myparams.push_back(dims.x);
this->myparams.push_back(dims.y);
this->params = params;
this->dims = dims;
N = 2;
itmax = N * 1000;
usingAorB = 2;
}
MyPowell::MyPowell()
{
usingAorB = 3;
}
double MyPowell::obj(vector<double> &myparams)
{
if (1 == usingAorB)
{
vector<Point2d> ppts = Dewarp::projectKeypoints(keypoint_index, myparams);
double total = 0;
for (int i = 0; i < ppts.size(); i++)
{
double x = dstpoints[i].x - ppts[i].x;
double y = dstpoints[i].y - ppts[i].y;
total += (x * x + y * y);
}
return total;
}
else if(2 == usingAorB)
{
dims.x = myparams[0];
dims.y = myparams[1];
//cout << "dims.x " << dims.x << " dims.y " << dims.y << endl;
vector<Point2d> vdims = { dims };
vector<Point2d> proj_br = Dewarp::projectXY(vdims, params);
double total = 0;
double x = dst_br.x - proj_br[0].x;
double y = dst_br.y - proj_br[0].y;
total += (x * x + y * y);
return total;
}
return 0;
}
void MyPowell::powell(vector<double> &x, vector<vector<double>> &direc, double ftol, double &fval)
{
vector<double> x1;
vector<double> x2;
vector<double> direc1;
int myitmax = 20;
if(N>500)
myitmax = 10;
else if (N > 300)
{
myitmax = 15;
}
double fx2, t, fx, dum, delta;
fval = obj(x);
int bigind;
for (int j = 0; j < N; j++)
{
x1.push_back(x[j]);
}
int iter = 0;
while (true)
{
do
{
do
{
iter += 1;
fx = fval;
bigind = 0;
delta = 0.0;
for (int i = 0; i < N; i++)
{
direc1 = direc[i];
fx2 = fval;
linmin(x, direc1, N, fval);
if (fabs(fx2 - fval) > delta)
{
delta = fabs(fx2 - fval);
bigind = i;
}
}
if (2.0 * fabs(fx - fval) <= ftol * (fabs(fx) + fabs(fval)) + 1e-7)
{
erase(direc1, x2, x1);
return;
}
if (iter >= itmax)
{
cout << "powell exceeding maximum iterations" << endl;
return;
}
if (!x2.empty())
{
x2.clear();
}
for (int j = 0; j < N; j++)
{
x2.push_back(2.0*x[j] - x1[j]);
direc1[j] = x[j] - x1[j];
x1[j] = x[j];
}
myitmax--;
cout << fx2 << endl;
fx2 = obj(x2);
if (myitmax < 0)
return;
} while (fx2 >= fx);
dum = fx - 2 * fval + fx2;
t = 2.0*dum*pow((fx - fval - delta), 2) - delta * pow((fx - fx2), 2);
} while (t >= 0.0);
linmin(x, direc1, N, fval);
direc[bigind] = direc1;
}
}
double MyPowell::sign(double a)//, double b)
{
if (a > 0.0)
{
return 1;
}
else
{
if (a < 0.0)
{
return -1;
}
}
return 0;
}
double MyPowell::sqr(double a)
{
return a * a;
}
void MyPowell::linmin(vector<double>& p, vector<double>& xit, int n, double &fret)
{
double tol = 1e-2;
ncom = n;
pcom = p;
xicom = xit;
double ax = 0.0;
double xx = 1.0;
double bx = 0.0;
double fa, fb, fx, xmin;
mnbrak(ax, xx, bx, fa, fx, fb);
fret = brent(ax, xx, bx, xmin, tol);
for (int i = 0; i < n; i++)
{
xit[i] = (xmin * xit[i]);
p[i] += xit[i];
}
}
void MyPowell::mnbrak(double & ax, double & bx, double & cx,
double & fa, double & fb, double & fc)
{
const double GOLD = 1.618034, GLIMIT = 110.0, TINY = 1e-20;
double val, fw, tmp2, tmp1, w, wlim;
double denom;
fa = f1dim(ax);
fb = f1dim(bx);
if (fb > fa)
{
val = ax;
ax = bx;
bx = val;
val = fb;
fb = fa;
fa = val;
}
cx = bx + GOLD * (bx - ax);
fc = f1dim(cx);
int iter = 0;
while (fb >= fc)
{
tmp1 = (bx - ax) * (fb - fc);
tmp2 = (bx - cx) * (fb - fa);
val = tmp2 - tmp1;
if (fabs(val) < TINY)
{
denom = 2.0*TINY;
}
else
{
denom = 2.0*val;
}
w = bx - ((bx - cx)*tmp2 - (bx - ax)*tmp1) / (denom);
wlim = bx + GLIMIT * (cx - bx);
if ((bx - w) * (w - cx) > 0.0)
{
fw = f1dim(w);
if (fw < fc)
{
ax = bx;
fa = fb;
bx = w;
fb = fw;
return;
}
else if (fw > fb)
{
cx = w;
fc = fw;
return;
}
w = cx + GOLD * (cx - bx);
fw = f1dim(w);
}
else
{
if ((cx - w)*(w - wlim) >= 0.0)
{
fw = f1dim(w);
if (fw < fc)
{
bx = cx;
cx = w;
w = cx + GOLD * (cx - bx);
fb = fc;
fc = fw;
fw = f1dim(w);
}
}
else if ((w - wlim)*(wlim - cx) >= 0.0)
{
w = wlim;
fw = f1dim(w);
}
else
{
w = cx + GOLD * (cx - bx);
fw = f1dim(w);
}
}
ax = bx;
bx = cx;
cx = w;
fa = fb;
fb = fc;
fc = fw;
}
}
double MyPowell::f1dim(double x)
{
vector<double> xt;
for (int j = 0; j < ncom; j++)
{
xt.push_back(pcom[j] + x * xicom[j]);
}
return obj(xt);
}
double MyPowell::brent(double ax, double bx, double cx, double & xmin, double tol = 1.48e-8)
{
const double CGOLD = 0.3819660, ZEPS = 1.0e-4;
int itmax = 500;
double a = MIN(ax, cx);
double b = MAX(ax, cx);
double v = bx;
double w = v, x = v;
double deltax = 0.0;
double fx = f1dim(x);
double fv = fx;
double fw = fx;
double rat = 0, u = 0, fu;
int iter;
int done;
double dx_temp, xmid, tol1, tol2, tmp1, tmp2, p;
for (iter = 0; iter < 500; iter++)
{
xmid = 0.5 * (a + b);
tol1 = tol * fabs(x) + ZEPS;
tol2 = 2.0*tol1;
if (fabs(x - xmid) <= (tol2 - 0.5*(b - a)))
break;
done = -1;
if (fabs(deltax) > tol1)
{
tmp1 = (x - w) * (fx - fv);
tmp2 = (x - v) * (fx - fw);
p = (x - v) * tmp2 - (x - w) * tmp1;
tmp2 = 2.0 * (tmp2 - tmp1);
if (tmp2 > 0.0)
p = -p;
tmp2 = fabs(tmp2);
dx_temp = deltax;
deltax = rat;
if ((p > tmp2 * (a - x)) && (p < tmp2 * (b - x)) &&
fabs(p) < fabs(0.5 * tmp2 * dx_temp))
{
rat = p / tmp2;
u = x + rat;
if ((u - a) < tol2 || (b - u) < tol2)
{
rat = fabs(tol1) * sign(xmid - x);
}
done = 0;
}
}
if(done)
{
if (x >= xmid)
{
deltax = a - x;
}
else
{
deltax = b - x;
}
rat = CGOLD * deltax;
}
if (fabs(rat) >= tol1)
{
u = x + rat;
}
else
{
u = x + fabs(tol1) * sign(rat);
}
fu = f1dim(u);
if (fu > fx)
{
if (u < x)
{
a = u;
}
else
{
b = u;
}
if (fu <= fw || w == x)
{
v = w;
w = u;
fv = fw;
fw = fu;
}
else if (fu <= fv || v == x || v == w)
{
v = u;
fv = fu;
}
}
else
{
if (u >= x)
a = x;
else
b = x;
v = w;
w = x;
x = u;
fv = fw;
fw = fx;
fx = fu;
}
}
if(iter > itmax)
cout << "\n Brent exceed maximum iterations.\n\n";
xmin = x;
return fx;
}
vector<double> MyPowell::usePowell()
{
ftol = 1e-4;
vector<vector<double>> xi;
for (int i = 0; i < N; i++)
{
vector<double> xii;
for (int j = 0; j < N; j++)
{
xii.push_back(0);
}
xii[i]=(1.0);
xi.push_back(xii);
}
double fret = 0;
powell(myparams, xi, ftol, fret);
//for (int i = 0; i < xi.size(); i++)
//{
// double a = obj(xi[i]);
// if (fret > a)
// {
// fret = a;
// myparams = xi[i];
// }
//}
cout << "final result" << fret << endl;
return myparams;
}
void MyPowell::erase(vector<double>& pbar, vector<double>& prr, vector<double>& pr)
{
for (int i = 0; i < pbar.size(); i++)
{
pbar[i] = 0;
}
for (int i = 0; i < prr.size(); i++)
{
prr[i] = 0;
}
for (int i = 0; i < pr.size(); i++)
{
pr[i] = 0;
}
}
I used PRAXIS library, because it doesn't need derivative information and is fast.
I modified the code a little to my needs and now it is faster than original version written in Python.
I'm using this function to convert a normalized value between 0 and 1 to an RGB value depending on the JET colormap.
std::vector<double> mapJet(double v, double vmin, double vmax)
{
if (v < vmin)
v = vmin;
if (v > vmax)
v = vmax;
double dr, dg, db;
if (v < 0.1242) {
db = 0.504 + ((1.-0.504) / 0.1242)*v;
dg = dr = 0.;
} else if (v < 0.3747) {
db = 1.;
dr = 0.;
dg = (v - 0.1242) * (1. / (0.3747-0.1242));
} else if (v < 0.6253) {
db = (0.6253 - v) * (1. / (0.6253-0.3747));
dg = 1.;
dr = (v - 0.3747) * (1. / (0.6253-0.3747));
} else if (v < 0.8758) {
db = 0.;
dr = 1.;
dg = (0.8758 - v) * (1. / (0.8758-0.6253));
} else {
db = 0.;
dg = 0.;
dr = 1. - (v - 0.8758) * ((1.-0.504) / (1.-0.8758));
}
return std::vector<double> { 255 * dr, 255 * dg, 255 * db };
}
My aim is to find the function double v = mapJet_inv(R,G,B). That is to say, I convert an RGB color to a normalized value between 0 and 1 depending on the colormap. I tried to start from the end of the mapJet function, however I didn't know how to specify the ranges of the R G B components.
Maybe I'm doing this badly. I will appreciate your help.
Thank you
vector<float> colors_to_value(vector<float> colors_tab)
{
double v ,db,dg,dr; v=db=dg=dr=0; vector<float> values_result;
for(int i=0;i<colors_tab.size();i++)
{
dr=colors_tab(i,0)/255.;
dg=colors_tab(i,1)/255.;
db=colors_tab(i,2)/255.;
if ( dg == 0. && dr == 0. ) {
v = (db - 0.504) / (1.-0.504) * 0.1242; // a revoir
}
else if ( db == 1. && dr == 0. ) {
v = dg/4. + 0.1242;
}
else if (db==0 && dr==1)
{
v = 0.8758 -dg*(1. / (0.8758-0.6253)) ;
}
else if ( db==0 && dg ==0)
{
v =( 1. - dr ) / ((1.-0.504) / (1.-0.8758)) + 0.8758;
}
else{
float val1= 0.6253 - db/(1. / (0.6253-0.3747)) ;
float val2=dr/ (1. / (0.6253-0.3747)) + 0.3747;
// v=(val1+val2)/2.;
if (val1>val2)
v=val1;
}
if(v<0) v=0;
values_result.push_back(v);
}
return values_result;
}
lastly, I run into a very crazy Segfault. I have nothing done to my source code, the only thing I might have done is updated my QT Creator and MinGW. Now my program causes a segmentation fault, before that it works perfectly.
void Parameter::calculateKeyframes() {
auto kfs = Bezier::calculateControlPoints(keyframes.values());
for (auto kf : kfs) {
setKeyframe(kf);
}
paramUpdate();
}
When it runs this function with a valid "keyframes" map, I know it thanks to debugging, it crashes in the Bezier::calculateControlPoints(QList) function at the marked line below.
QList<Keyframe> calculateControlPoints(QList<Keyframe> keyframes) {
if (keyframes.size() < 2) {
return keyframes;
}
int n = keyframes.size();
for (int i = 0; i<n; i++) {
Keyframe last_kf(0, ValueDouble(0.0));
Keyframe kf;
kf = keyframes.at(i);
Keyframe next_kf(0, ValueDouble(0.0));
if (-1 < i-1) last_kf = keyframes[i-1];
else last_kf.frame = -1;
if (keyframes.size() > i+1) next_kf = keyframes[i+1];
else next_kf.frame = -1;
if (kf.mode == Keyframe::STEP || kf.mode == Keyframe::LINEAR) continue;
if (next_kf.frame > -1 && (kf.mode == Keyframe::EASEIN || (kf.mode == Keyframe::EASE && last_kf.frame < 0))) {
double vecx_TtN = (double)next_kf.frame - (double)kf.frame; // vx = nx - x
double vecy_TtN = next_kf.data.toDouble() - kf.data.toDouble(); // vy = ny - y
kf.control2x = (double)kf.frame + vecx_TtN / 4.5; // x = x + vx / 4.5
kf.control2y = (vecy_TtN / vecx_TtN) * (kf.control2x - kf.frame) + kf.data.toDouble(); // y = m * x + t
} else if (last_kf.frame > -1 && (kf.mode == Keyframe::EASEOUT || (kf.mode == Keyframe::EASE && next_kf.frame < 0))) {
double vecx_TtL = (double)last_kf.frame - (double)kf.frame; // vx = lx - x
double vecy_TtL = last_kf.data.toDouble() - kf.data.toDouble(); // vy = ly - y
kf.control1x = (double)kf.frame + vecx_TtL / 4.5; // x = x + vx / 4.5
kf.control1y = (vecy_TtL / vecx_TtL) * (kf.control1x - kf.frame) + kf.data.toDouble(); // y = m * x + t
} else if (kf.mode == Keyframe::EASE && last_kf.frame > -1 && next_kf.frame > -1) {
double vecx_TtL = (double)last_kf.frame - (double)kf.frame; // vx = lx - x
double vecx_TtN = (double)next_kf.frame - (double)kf.frame; // vx = nx - x
double vecx_LtN = (double)next_kf.frame - (double)last_kf.frame; // vx = nx - lx
/* ---> */ double vecy_LtN = next_kf.data.toDouble() - last_kf.data.toDouble(); // vy = ny - ly
kf.control1x = (double)kf.frame + vecx_TtL / 4.5; // x = x + vx / 4.5
kf.control2x = (double)kf.frame + vecx_TtN / 4.5; // x = x + vx / 4.5
kf.control1y = (vecy_LtN/vecx_LtN) * (kf.control1x - kf.frame) + kf.data.toDouble(); // y = m * x + t
kf.control2y = (vecy_LtN/vecx_LtN) * (kf.control2x - kf.frame) + kf.data.toDouble(); // y = m * x + t
}
keyframes[i] = kf;
}
return keyframes;
}
It is caused in the second loop run because the "QList keyframes" has in its member with the index 0 (that means in the second run this member is also copied into "last_kf") an invalid pointer-address in the Keyframes "data" pointer. Now my question is why is data now a invalid pointer... in Parameter::calculateKeyframes() it wasn't.
Here my Keyframe.cpp (if it is important):
#include "keyframe.h"
#include "value.h"
#include "valuedouble.h"
#include <iostream>
Keyframe::Keyframe(long frame, Value v) : frame(frame), control1x(frame), control2x(frame), data(v), control1y(v), control2y(v) {
}
Keyframe::Keyframe() : Keyframe(0.0, ValueDouble(0.0)) {}
void Keyframe::toPipeKF(tutorial::Keyframe* k) {
k->set_mode((tutorial::Keyframe_Mode)(int)mode);
k->set_frame(frame);
k->set_data((const char*)data.toByteArray());
k->set_control1x(control1x);
k->set_control1y(control1y.toByteArray());
k->set_control2x(control2x);
k->set_control2y(control2y.toByteArray());
}
Keyframe.h:
#ifndef KEYFRAME_H
#define KEYFRAME_H
#include "pipeendpoint.h"
#include "value.h"
class Keyframe {
public:
Keyframe(long frame, Value v);
Keyframe();
enum Mode {
STEP,
LINEAR,
EASEIN,
EASE,
EASEOUT,
EASEFIX,
EASECUSTOM
};
Mode mode = EASE;
Value data;
long frame;
double control1x = 0;
Value control1y;
double control2x = 0;
Value control2y;
void toPipeKF(tutorial::Keyframe* kf);
};
#endif // KEYFRAME_H
I'm trying to rewrite a piece of code that includes C++ dll calls from VBA to VB.NET.
In particular there is a C++ function I'm calling in the dll that performs some actions on a couple of bidimensional arrays of float is:
int __stdcall FindPolarization(int PointsTheta, int PointsPhi, float* Real1, float* Imag1 = nullptr)
{
double Max[4] = { -999, -999, -999, -999 }; // Max values
long MaxPos[4][2] = { -999, -999, // Max Theta and Max Phi
-999, -999,
-999, -999,
-999, -999 };
float* Pointers[4][2];
double DeltaTheta = static_cast<double>(180.0 / PointsTheta);
double DeltaPhi = static_cast<double>(360.0 / PointsPhi);
vector<vector<vector<double>>> Ampl;
// Setup
Pointers[0][0] = Real1;
Pointers[0][1] = Imag1;
Pointers[1][0] = Real2;
Pointers[1][1] = Imag2;
Pointers[2][0] = Real3;
Pointers[2][1] = Imag3;
Pointers[3][0] = Real4;
Pointers[3][1] = Imag4;
if (Real3 != nullptr && Real4 != nullptr && Imag3 != nullptr && Imag4 != nullptr)
{
Ampl.resize(4, vector<vector<double>>(PointsTheta + 1, vector<double>(PointsPhi, 0)));
Real3 = nullptr; Imag3 = nullptr; Real4 = nullptr; Imag4 = nullptr;
}
else
{
Ampl.resize(2, vector<vector<double>>(PointsTheta + 1, vector<double>(PointsPhi, 0)));
}
Real1 = nullptr; Imag1 = nullptr; Real2 = nullptr; Imag2 = nullptr;
// Coordinates transformation + Maximum storage
Concurrency::parallel_for(0, PointsPhi, [&](int j)
{
double PhiRad = j * DeltaPhi * Deg2Rad;
double CosPhi = cos(PhiRad);
double SinPhi = sin(PhiRad);
int ind;
pair<double, double> AmplCoCr;
for (int i = 0; i <= PointsTheta; i++)
{
ind = j * (PointsTheta + 1) + i;
for (int k = 0; k < static_cast<int>(Ampl.size()); k = k + 2)
{
AmplCoCr = AmplCalc(ind, Pointers[k][0], Pointers[k][1], Pointers[k + 1][0], Pointers[k + 1][1], CosPhi, SinPhi);
Ampl[k][i][j] = AmplCoCr.first;
Ampl[k + 1][i][j] = AmplCoCr.second;
if (Ampl[k][i][j] > Max[k])
{
Max[k] = Ampl[k][i][j];
MaxPos[k][0] = i;
MaxPos[k][1] = j;
}
if (Ampl[k + 1][i][j] > Max[k + 1])
{
Max[k + 1] = Ampl[k + 1][i][j];
MaxPos[k + 1][0] = i;
MaxPos[k + 1][1] = j;
}
}
}
});
double A = max(max(Max[0], Max[1]), max(Max[2], Max[3]));
if (A > Max[1] && A > Max[2] && A > Max[3]) return 45;
else if (A > Max[0] && A > Max[2] && A > Max[3]) return 135;
else if (A > Max[0] && A > Max[1] && A > Max[3]) return 90;
return 0; // else if (A > Max[0] && A > Max[1] && A > Max[2])
}
pair<double, double> AmplCalc(int index, float* RealCo, float* ImagCo, float* RealCr, float* ImagCr, double CosPhi, double SinPhi)
{
double A, B;
const double RealCoij = static_cast<double>(RealCo[index]);
const double RealCrij = static_cast<double>(RealCr[index]);
const double ImagCoij = static_cast<double>(ImagCo[index]);
const double ImagCrij = static_cast<double>(ImagCr[index]);
A = RealCoij * CosPhi + RealCrij * SinPhi;
B = ImagCoij * CosPhi + ImagCrij * SinPhi;
double Co = 10 * log10(A * A + B * B);
A = (RealCoij * SinPhi * (-1) + RealCrij * CosPhi);
B = (ImagCoij * SinPhi * (-1) + ImagCrij * CosPhi);
double Cr = 10 * log10(A * A + B * B);
return make_pair(Co, Cr);
}
which in the VBA environment is imported with:
Private Declare Function FindPolarization Lib "EvalFunc.dll" (ByVal PointsTheta As Long, ByVal PointsPhi As Long, ByRef RealLev1 As Single, ByRef ImagLev1 As Single = 0) As Long
and called in the code through:
Dim RealLev1() As Single, ImagLev1() As Single
Dim PolMax As Long, FFThetaPoints As Long, FFPhiPoints As Long
' Arrays are filled here through a function that determines their dimensions and values
FFThetaPoints = UBound(RealLev1, 1)
FFPhiPoints = UBound(RealLev1, 2)
PolMax = FindPolarization(FFThetaPoints, FFPhiPoints, RealLev1(0, 0), ImagLev1(0, 0))
This works on VBA, but I've been trying to translate it into VB.NET and failed miserably.
Provided that I can't change the C++ code inside the dll, I have stopped at the following code.
The import of the function looks like:
<DllImport("myDll.dll", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function FindPolarization(ByVal PointsTheta As Integer, ByVal PointsPhi As Integer, ByRef RealLev1 As Single, _
Optional ByRef ImagLev1 As Single = Nothing) As Integer
End Function
And the code calling it would be:
Dim FFThetaPoints As Integer, FFPhiPoints As Integer, PolMax As Integer
Dim RealLev1(,) As Single = Array.CreateInstance(GetType(Single), 1, 1)
Dim ImagLev1(,) As Single = Array.CreateInstance(GetType(Single), 1, 1)
FFThetaPoints = UBound(RealLev1, 1)
FFPhiPoints = UBound(RealLev1, 2)
PolMax = ImportDll.FindPolarization(FFThetaPoints, FFPhiPoints, RealLev1(0, 0), ImagLev1(0, 0))
Now, those array are System.Array type because of a particular function that requires them to be so.
While in VBA I get some result, in VB.NET I obtain other ones. I think this has something to do with how I declare the Single arrays, but I am not sure.
What am I doing wrong?
I have to give all the credit to #Craig here.
VBA and VB.NET have indeed different matrix addressing logics (column major vs. row major), so I had to transpose all the 2D arrays, without swapping FFThetaPoints and FFPhiPoints.
It is worth mentioning that I tried using the Excel.Application Worksheetfunction.Transpose method, which didn't work as expected. So I had to write my own piece of code to transpose the matrices.
I am using this code for calculating sunrise and sunset times.
// Get the daylight status of the current time.
bool
SunLight::CalculateDaylightStatus()
{
// Calculate the current time of day.
time_t currentTime = time(NULL);
m_LocalTime = localtime(¤tTime);
// Initialize the sunrise and set times.
*m_Sunrise = *m_LocalTime;
*m_Sunset = *m_LocalTime;
// Flags to check whether sunrise or set available on the day or not.
m_IsSunrise = false;
m_IsSunset = false;
m_RiseAzimuth = 0.0;
m_SetAzimuth = 0.0;
for (unsigned int i = 0; i < 3; i++)
{
m_RightAscention[i] = 0.0;
m_Decension[i] = 0.0;
m_VHz[i] = 0.0;
}
for (unsigned int i = 0; i < 2; i++)
{
m_SunPositionInSky[i] = 0.0;
m_RiseTime[i] = 0;
m_SetTime[i] = 0;
}
// Calculate the sunrise and set times.
CalculateSunRiseSetTimes();
return (mktime(m_LocalTime) >= mktime(m_Sunrise) && mktime(m_LocalTime) < mktime(m_Sunset))
? true
: false;
}
//---------------------------------------------------------------------
bool
SunLight::CalculateSunRiseSetTimes()
{
double zone = timezone/3600 - m_LocalTime->tm_isdst;
// Julian day relative to Jan 1.5, 2000.
double jd = GetJulianDay() - 2451545;
if ((Sign(zone) == Sign(m_Config->Longitude())) && (zone != 0))
{
return false;
}
double tz = zone / 24;
// Centuries since 1900.0
double ct = jd / 36525 + 1;
// Local sidereal time.
double t0 = LocalSiderealTimeForTimeZone(jd, tz, m_Config->Longitude()/360);
// Get sun position at start of day.
jd += tz;
// Calculate the position of the sun.
CalculateSunPosition(jd, ct);
double ra0 = m_SunPositionInSky[0];
double dec0 = m_SunPositionInSky[1];
// Get sun position at end of day.
jd += 1;
// Calculate the position of the sun.
CalculateSunPosition(jd, ct);
double ra1 = m_SunPositionInSky[0];
double dec1 = m_SunPositionInSky[1];
// make continuous
if (ra1 < ra0)
ra1 += 2 * M_PI;
m_RightAscention[0] = ra0;
m_Decension[0] = dec0;
// check each hour of this day
for (int k = 0; k < 24; k++)
{
m_RightAscention[2] = ra0 + (k + 1) * (ra1 - ra0) / 24;
m_Decension[2] = dec0 + (k + 1) * (dec1 - dec0) / 24;
m_VHz[2] = TestHour(k, t0, m_Config->Latitude());
// advance to next hour
m_RightAscention[0] = m_RightAscention[2];
m_Decension[0] = m_Decension[2];
m_VHz[0] = m_VHz[2];
}
// Update the tm structure with time values.
m_Sunrise->tm_hour = m_RiseTime[0];
m_Sunrise->tm_min = m_RiseTime[1];
m_Sunset->tm_hour = m_SetTime[0];
m_Sunset->tm_min = m_SetTime[1];
// neither sunrise nor sunset
if ((!m_IsSunrise) && (!m_IsSunset))
{
// Sun down all day.
if (m_VHz[2] < 0)
m_IsSunset = true;
// Sun up all day.
else
m_IsSunrise = true;
}
return true;
}
//---------------------------------------------------------------------
int
SunLight::Sign(double value)
{
if (value > 0.0)
return 1;
else if (value < 0.0)
return -1;
else
return 0;
}
//---------------------------------------------------------------------
// Local Sidereal Time for zone.
double
SunLight::LocalSiderealTimeForTimeZone(double jd, double z, double lon)
{
double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
s = s / 86400;
s = s - floor(s);
return s * 360 * cDegToRad;
}
//---------------------------------------------------------------------
// Determine Julian day from calendar date
// (Jean Meeus, "Astronomical Algorithms", Willmann-Bell, 1991).
double
SunLight::GetJulianDay()
{
int month = m_LocalTime->tm_mon + 1;
int day = m_LocalTime->tm_mday;
int year = 1900 + m_LocalTime->tm_year;
bool gregorian = (year < 1583) ? false : true;
if ((month == 1) || (month == 2))
{
year = year - 1;
month = month + 12;
}
double a = floor((double)year / 100);
double b = 0;
if (gregorian)
b = 2 - a + floor(a / 4);
else
b = 0.0;
double jd = floor(365.25 * (year + 4716))
+ floor(30.6001 * (month + 1))
+ day + b - 1524.5;
return jd;
}
//---------------------------------------------------------------------
// Sun's position using fundamental arguments
// (Van Flandern & Pulkkinen, 1979).
void
SunLight::CalculateSunPosition(double jd, double ct)
{
double g, lo, s, u, v, w;
lo = 0.779072 + 0.00273790931 * jd;
lo = lo - floor(lo);
lo = lo * 2 * M_PI;
g = 0.993126 + 0.0027377785 * jd;
g = g - floor(g);
g = g * 2 * M_PI;
v = 0.39785 * sin(lo);
v = v - 0.01 * sin(lo - g);
v = v + 0.00333 * sin(lo + g);
v = v - 0.00021 * ct * sin(lo);
u = 1 - 0.03349 * cos(g);
u = u - 0.00014 * cos(2 * lo);
u = u + 0.00008 * cos(lo);
w = -0.0001 - 0.04129 * sin(2 * lo);
w = w + 0.03211 * sin(g);
w = w + 0.00104 * sin(2 * lo - g);
w = w - 0.00035 * sin(2 * lo + g);
w = w - 0.00008 * ct * sin(g);
// compute sun's right ascension
s = w / sqrt(u - v * v);
m_SunPositionInSky[0] = lo + atan(s / sqrt(1 - s * s));
// ...and declination
s = v / sqrt(u);
m_SunPositionInSky[1] = atan(s / sqrt(1 - s * s));
}
//---------------------------------------------------------------------
// Test an hour for an event.
double
SunLight::TestHour(int k, double t0, double prmLatitude)
{
double ha[3];
double a, b, c, d, e, s, z;
double time;
double az, dz, hz, nz;
int hr, min;
ha[0] = t0 - m_RightAscention[0] + k * cK1;
ha[2] = t0 - m_RightAscention[2] + k * cK1 + cK1;
ha[1] = (ha[2] + ha[0]) / 2; // hour angle at half hour
m_Decension[1] = (m_Decension[2] + m_Decension[0]) / 2; // declination at half hour
s = sin(prmLatitude * cDegToRad);
c = cos(prmLatitude * cDegToRad);
z = cos(90.833 * cDegToRad); // refraction + sun semi-diameter at horizon
if (k <= 0)
m_VHz[0] = s * sin(m_Decension[0]) + c * cos(m_Decension[0]) * cos(ha[0]) - z;
m_VHz[2] = s * sin(m_Decension[2]) + c * cos(m_Decension[2]) * cos(ha[2]) - z;
if (Sign(m_VHz[0]) == Sign(m_VHz[2]))
return m_VHz[2]; // no event this hour
m_VHz[1] = s * sin(m_Decension[1]) + c * cos(m_Decension[1]) * cos(ha[1]) - z;
a = 2 * m_VHz[0] - 4 * m_VHz[1] + 2 * m_VHz[2];
b = -3 * m_VHz[0] + 4 * m_VHz[1] - m_VHz[2];
d = b * b - 4 * a * m_VHz[0];
if (d < 0)
return m_VHz[2]; // no event this hour
d = sqrt(d);
e = (-b + d) / (2 * a);
if ((e > 1) || (e < 0))
e = (-b - d) / (2 * a);
time = (double)k + e + (double)1 / (double)120; // time of an event
hr = (int)floor(time);
min = (int)floor((time - hr) * 60);
hz = ha[0] + e * (ha[2] - ha[0]); // azimuth of the sun at the event
nz = -cos(m_Decension[1]) * sin(hz);
dz = c * sin(m_Decension[1]) - s * cos(m_Decension[1]) * cos(hz);
az = atan2(nz, dz) / cDegToRad;
if (az < 0) az = az + 360;
if ((m_VHz[0] < 0) && (m_VHz[2] > 0))
{
m_RiseTime[0] = hr;
m_RiseTime[1] = min;
m_RiseAzimuth = az;
m_IsSunrise = true;
}
if ((m_VHz[0] > 0) && (m_VHz[2] < 0))
{
m_SetTime[0] = hr;
m_SetTime[1] = min;
m_SetAzimuth = az;
m_IsSunset = true;
}
return m_VHz[2];
}
//---------------------------------------------------------------------
I need to introduce altitude in the formula which gives more accurate result. Can someone give me a quick solution what I have to modify to add altitude in the formula?
That algorithm is nowhere near calculating the times of sunrise and sunset. What you need is Jean Meeus' book "Astronomical Algorithms". You will need to account for the observer's longitude and latitude, the difference between dynamical time and universal time, and the eccentricity of the Earth's orbit to obtain even a low accuracy result.
This seems to be called sunrise equation. The formulas in that Wiki article are unbelievably simple, and they do account for the geographic location.