Translating the passage of a reference to a DLL from VBA to VB.NET - c++

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.

Related

Passing Arrays through Fuctions - "Error: Cannot Convert 'float**' to 'float*' for argument '1'"

Long time Reader, First time Asker.
So I'm working on a coding project of which the long term goal is to make a solar system simulator. The idea is that that it whips up a randomized solar system with a few rules like 'at formation the first planet after the frostline has to be the largest gas giant' etc, and calculates the orbits to check for stability.
Obviously it's not done yet, I'm having some trouble with using the arrays in the subroutines. I know that you can't directly take arrays in and out of functions, but you can take pointers to said arrays in and out of functions if you do it right.
I apparently have not done it right below. I've tried to comment and make the code as readable as possible, here it is.
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <tuple>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <complex>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <algorithm>
//#include "mpi.h"
using namespace std;
double MyRandom(){
//////////////////////////
//Random Number Generator
//Returns number between 0-99
//////////////////////////
double y = 0;
unsigned seed = time(0);
srand(seed);
uint64_t x = rand();
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
x = (1070739 * x) % 2199023255530;
y = x / 21990232555.31 ;
return y;
}
////////////////////////
///////////////////////
tuple< char& , float& , float& , float& , int& > Star(){
////////////////////////////
//Star will generate a Star
//Randomly or User Selected
//Class, Luminosity, Probability, Radius, Mass, Temperature
//Stars always take up 99% of the mass of the system.
///////////////////////////
char Class;
string Choice;
float L, R, M;
int T;
tuple< char& , float& , float& , float& , int& > star( Class = 'i', L = 1 , R = 1 , M = 1 , T = 3000) ;
cout << "Select Star Class (OBAFGKM) or Select R for Random: ";
cin >> Choice;
if ( Choice == "R" ) {
double y;
y = MyRandom();
if (y <= 0.003) Class = 'O';
if ((y > 0.003) && (y <= 0.133)) Class = 'B';
if ((y > 0.133) && (y <= 0.733)) Class = 'A';
if ((y > 0.733) && (y <= 3.733)) Class = 'F';
if ((y > 3.733) && (y <= 11.333)) Class = 'G';
if ((y > 11.333) && (y <= 23.433)) Class = 'K';
else Class = 'M';
}
if (Class == 'O') {
L = 30000;
R = 0.0307;
M = 16;
T = 30000;
}
if (Class == 'B') {
L = 15000;
R = 0.0195;
M = 9;
T = 20000;
}
if (Class == 'A') {
L = 15;
R = 0.00744;
M = 1.7;
T = 8700;
}
if (Class == 'F') {
L = 3.25;
R = 0.00488;
M = 1.2;
T = 6750;
}
if (Class == 'G') {
L = 1;
R = 0.00465;
M = 1;
T = 5700;
}
if (Class == 'K') {
L = 0.34;
R = 0.00356;
M = 0.62;
T = 4450;
}
if (Class == 'M') {
L = 0.08;
R = 0.00326;
M = 0.26;
T = 3000;
}
return star;
}
////////////
////////////
float* Planet( float &L, float &R, float &M, int &T, int &n){
///////////////////////////
//Planet generates the Planets
//Random 1 - 10, Random distribution 0.06 - 6 JAU unless specified by User
//Frost line Calculated, First Planet after Frost line is the Jupiter
//The Jupiter will have the most mass of all Jovian worlds
//Otherwise divided into Jovian and Terrestrial Worlds, Random Masses within groups
//Also calculates if a planet is in the Habitable Zone
////////////////////////////
float frostline, innerCHZ, outerCHZ;
float a = 0.06; // a - albedo
float m = M / 100; //Mass of the Jupiter always 1/100th mass of the Star.
float sys[n];
float* system[n][5] = {{0}};
for (int i = 0 ; i < n ; i++){
sys[i] = MyRandom()/10 * 3; //Distances in terms of Sol AU
}
sort(sys, sys + n );
for (int i = 0 ; i < n ; i++){
system[i][0] = &sys[i];
system[i][1] = 0; //system[i][0] is x, system[i][1] is y
}
frostline = (0.6 * T / 150) * (0.6 * T/150) * R / sqrt(1 - a);
innerCHZ = sqrt(L / 1.1);
outerCHZ = sqrt(L / 0.53);
for (int i = 0 ; i < n ; i++){
if (system[i][0] <= &frostline) {
float tmass = m * 0.0003 * MyRandom();
system[i][2] = &tmass ; //system[i][2] is mass, [3] is marker for the Jupter
system[i][3] = 0 ;
}
if ((system[i][0] >= &frostline) && (system[i-1][0] < &frostline)){
system[i][2] = &m ;
float J = 1;
system[i][3] = &J ;
}
if ((system[i][0] >= &frostline) && (system[i-1][0] >= &frostline)) {
float jmass = m * 0.01 * MyRandom();
system[i][2] = &jmass ;
system[i][3] = 0 ;
}
if ((system[i][0] >= &innerCHZ) && (system[i][0] <= &outerCHZ)){
float H = 1;
system[i][4] = &H;
}
else system[i][4] = 0; //[4] is habitable marker
}
return system[n][5];
}
////////////
////////////
float* Time( float *system , int n){
///////////////////////////
//Time advances the solar system.
//Plots the Orbits
//Uses MPI to spread it's calculations.
///////////////////////////
return system;
}
////////////
////////////
void FinalCheck( float system){
///////////////////////////
//Final Checks
//Reports if a Planet spent the whole Time in the Habitable Zone
///////////////////////////
/*for (int i = 0 ; i < row ; i++){
if (system[i][4] == 1.0) {
cout << "Planet " << i << " in this system is Habitable." ;
}
// The Habitable stat only means liquid water can exist on the surface
// Add pi if planet enters habitable zone, minus 1 if it leaves.
// If planet was habitable but left, assuming all life was destroyed
}
*/
}
////////////
int main(){
char Class;
int T;
float L, R, M;
tuple< char , float , float , float , int > star( Class , L , R , M , T );
star = Star();
int n = MyRandom()/10 + 1;
float * system[n][5] = {{0}};
float system1[n][5] = {{0}};
system[n][5] = Planet( L , R , M, T, n);
for (int i = 0 ; i < 100 ; i++) {
system1[n][5] = Time( *system, n );
system[n][5] = &system1[n][5];
}
FinalCheck( *system[n][5]);
///////////////////////////
//Report cleans everything up and gives the results
//Shows the plot, lists the Planets
//Reports the Positions and Masses of all Planets
//Reports which was the Jupiter and which if any were Habitable
//////////////////////////
return 0;
}
The problem is when I run a compiler over this line 227 gets flagged -
system1[n][5] = Time( *system, n );
With the following error:
error: cannot convert 'float**' to 'float*' for argument '1' to 'float* Time(float*, int)
I get that this means that the compiler things I'm trying to equate a pointer-to-a-pointer with a pointer, but I'm not sure how it arrived at that conclusion or how to fix it. I'd appreciate help with this, especially the second part. I also would love to hear anything about passing arrays through subroutines as apparently I'm not doing it right, or at least not well.
Update 1 : - Got the short-term fix in and the compiler makes it through but gives a segmentation fault (core dumped) error when I try to run it. Looks like I have some reading and updates to do though with the namespace, the pointers, and possibly changing the arrays into vectors instead. Feels like if I concentrate on those first it might fix the segmentation error.
Your variable system is declared as
float * system[n][5] = {{0}};
which is a pointer to a 2D array (which will decay to float*** when passed to a function).
Your Time function is declared as
float* Time( float *system , int n);
where the 1st argument needs to be a float*.
That means this call
system1[n][5] = Time( *system, n );
should actually be something like
system1[n][5] = Time( **system, n );
That being said, there are a number of issues in your code.
To start off, don't do using namespace std;.
Also, this line float sys[n]; is not allowed. You can't have variable length arrays in c++.
float* system[n][5]
system here is a 2D array of float*s, not floats.
So, in other words, system decays to float***, *system decays to float**, **system decays to float*, and ***system decays to float.
So, the compiler is correct. You're passing what decays to a float** to Time() which expects a float*.
You're going to have to reconfigure your code to pass the right thing, whatever that is.
Side note: please be advised that the way you're creating arrays isn't valid C++ and may cause issues later.

C++ Induction Algorithm very slow and Dynamical Programming

I have a mathematical control problem which I solve through Backward induction. The mathematical problem is the following :
with K less than n.
And final conditions
What is J(0,0,0) ?
For this purpose I am using c++ and mingw 32 bit as a compiler.
The problem is the code (below) which solve the problem is an induction and does not provide any results if n,M > 15.
I have tried to launch n=M=100 for 4 days but no results.
Does anyone have a solution? Is it a compiler option to change (the processor memory is not enough)? The complexity is too big?
Here my code
const int n = 10;
const int M = 10;
double J_naive (double K, double Z, double W)
{
double J_tmp = exp(100.0);
double WGreaterThanZero = 0.0;
//Final condition : Boundaries
if (K == n)
{
if (W > 0) WGreaterThanZero = 1.0;
else WGreaterThanZero = 0.0;
if (Z >= WGreaterThanZero) return 0.0;
return exp(100.0);//Infinity
}
//Induction
else if (K < n)
{
double y;
for (int i = 0; i <= M; i++)
{
y = ((double) i)/M;
{
J_tmp = std::min (J_tmp, ((double) n)*y*y +
0.5*J_naive(K+1.0, Z+y, W + 1.0/sqrt(n)) +
0.5*J_naive(K+1.0, Z+y, W - 1.0/sqrt(n)) );
}
}
}
return J_tmp;
}
int main()
{
J_naive(0.0, 0.0, 0.0);
}
You can try the following, completely untested DP code. It needs around 24*n^3*M bytes of memory; if you have that much memory, it should run within a few seconds. If there is some value that will never appear as a true return value, you can get rid of seen_[][][] and use that value in result_[][][] to indicate that the subproblem has not yet been solved; this will reduce memory requirements by about a third. It's based on your code before you made edits to fix bugs.
const int n = 10;
const int M = 10;
bool seen_[n][n * M][2 * n]; // Initially all false
double result_[n][n * M][2 * n];
double J_naive(unsigned K, unsigned ZM, double W0, int Wdsqrtn)
{
double J_tmp = exp(100.0);
double WGreaterThanZero = 0.0;
double Z = (double) ZM / M;
double W = W0 + Wdsqrtn * 1./sqrt(n);
//Final condition : Boundaries
if (K == n)
{
if (W > 0) WGreaterThanZero = 1.0;
else WGreaterThanZero = 0.0;
if (Z >= WGreaterThanZero) return 0.0;
return exp(100.0);//Infinity
}
//Induction
else if (K < n)
{
if (!seen_[K][ZM][Wdsqrtn + n]) {
// Haven't seen this subproblem yet: compute the answer
for (int i = 0; i <= M; i++)
{
J_tmp = std::min (J_tmp, ((double) n)*i/M*i/M +
0.5*J_naive(K+1, ZM+i, W0, Wdsqrtn+1) +
0.5*J_naive(K+1, ZM+i, W0, Wdsqrtn-1) );
}
result_[K][ZM][Wdsqrtn + n] = J_tmp;
seen_[K][ZM][Wdsqrtn + n] = true;
}
}
return result_[K][ZM][Wdsqrtn + n];
}

Segmentation fault caused by copying QList

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

How to implement the deconv layer in caffe in the 3D filter manner?

I have a requirement to implement the forward computing of deconv layer in the 3D filter manner.
Here, by '3D filter manner', I mean convolution like the Gaussian filter in CV. In the contrast, the caffe implements the deconv in the gemm + col2im manner.
I find a similar question here. The guy wrote the code according the introduction in tranposed conv.
Image
He/She does not open the source code. So I finished my own one:
template <typename DataType> int deconv_cpu(
DataType *src, DataType *dst, DataType *para, DataType *bias,
int in_width, int in_height, int in_channel,
int out_width, int out_height, int out_channel,
int ks, int padding = 0, int step = 1) { // step indicates the stride
int col, row, ch_o, ch_i, x, y;
int r = (ks - 1) / 2; //radius;
DataType result;
DataType *output;
DataType *filter;
DataType *input;
int sim_width, sim_height, sim_pad, width_border, height_border;
sim_width = in_width * step - step + 1;
sim_height = in_height * step - step + 1;
sim_pad = ks - padding - 1;
width_border = sim_pad == 0 ? r : 0;
height_border = sim_pad == 0 ? r : 0;
for (row = height_border; row < (sim_height - height_border); row++)
for (col = width_border; col < (sim_width - width_border); col++)
{
for (ch_o = 0; ch_o < out_channel; ch_o++)
{
output = dst + ch_o * out_width * out_height;
result = 0;
for (ch_i = 0; ch_i < in_channel; ch_i++)
{
filter = para + ks * ks * (in_channel * ch_o + ch_i);
//filter = para + ks*ks * (out_channel * ch_i + ch_o);
input = src + ch_i * in_width * in_height;
for (x = -r; x <= r; x++)
{
for (y = -r; y <= r; y++)
{
if ((row + x) >= 0 && (col + y) >= 0 && (row + x) < sim_height && (col + y) < sim_width)
{
if ( (row + x) % step != 0 || (col + y) % step != 0) continue;
result += input[(row + x) / step * in_width + (col + y) / step] * filter[(x + r) * ks + (y + r)];
}
}
}
}
if (bias != NULL) result = result + bias[ch_o];
output[(row - height_border) * out_width + (col - width_border)] = result;
}
}
return 0;
}
I compare the result with the caffe's one:
const caffe::vector<caffe::shared_ptr<caffe::Blob<float> > > blobs = layers[i]->blobs();
float *filter = blobs[0]->mutable_cpu_data();
float *bias = blobs[1]->mutable_cpu_data();
caffe::shared_ptr<caffe::Blob<float> > blob;
blob = caffe_net->blob_by_name(np.bottom(0));
deconv_cpu(blob->mutable_cpu_data(), dst, filter, bias, width1,
height1, c1, width2, height2, c2, ks, pad, stride);
blob = caffe_net->blob_by_name(np.top(0));
if(compare(dst, blob->mutable_cpu_data()) == 0) printf("match\n");
else printf("do not match\n");
However, the code does not give the same result with the caffe's implementation.
Do anyone know what is wrong? Or any advises or comment on the code?
This issue is finally fixed by change the filter index:
filter[(r-x) * ks + (r-y)]

Get the side a player is looking on the block | bukkit

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