32 #define isfinite _finite 
   50   IndexSet(
unsigned int max_size) :
 
   51     size_(0), max_size_(max_size), data_(new unsigned int[max_size]) {}
 
   52   unsigned int get_size()
 const {
 
   58   unsigned int& operator[](
unsigned int n) {
 
   61   unsigned int operator[](
unsigned int n)
 const {
 
   64   void set_size(
unsigned int size) {
 
   67   bool exist(
unsigned int elem) {
 
   69     for(
unsigned int i = 0; i < size_; ++i) {
 
   70       if(data_[i] == elem) {
 
   77   bool insert(
unsigned int elem) {
 
   79     if((size_ < max_size_) && (
false == 
exist(elem))) {
 
   80       data_[size_++] = elem;
 
   85   bool remove(
unsigned int elem) {
 
   87     for(
unsigned int i = 0; i < size_; ++i) {
 
   88       if(data_[i] == elem) {
 
   90           memcpy(data_ + i, data_ + i + 1, (size_ - i - 1)*
sizeof(*data_));
 
  101   unsigned int max_size_;
 
  109   static double get_dist(
const Point *p0, 
const Point *p1) {
 
  111     double *coord_p0 = (
double*)p0;
 
  112     double *coord_p1 = (
double*)p1;
 
  113     for(
int n = 0; n < 3; ++n) {
 
  114       out += (coord_p1[n] - coord_p0[n]) * (coord_p1[n] - coord_p0[n]);
 
  118   static bool test_uniqueness(
const Point *bs_pos, 
int bs_pos_len, 
double eps) {
 
  121     for(i = bs_pos_len - 1; i >= 0; --i) {
 
  122       for(j = i - 1; j >= 0; --j) {
 
  123         if((fabs(bs_pos[i].x - bs_pos[j].x) < eps) && (fabs(bs_pos[i].y - bs_pos[j].y) < eps) &&
 
  124             (fabs(bs_pos[i].z - bs_pos[j].z) < eps)) {
 
  132   static double det_3by3(
const double mat[9]) {
 
  133     return mat[0] * (mat[4] * mat[8] - mat[5] * mat[7]) + mat[3] * (mat[2] * mat[7] - mat[1] * mat[8]) + mat[6] * (mat[1] * mat[5] - mat[2] * mat[4]);
 
  135   static double det_4by4(
const double mat[16]) {
 
  136     return mat[0] * mat[5] * mat[10] * mat[15] + mat[0] * mat[9] * mat[14] * mat[7] + mat[0] * mat[13] * mat[6] * mat[11] +
 
  137            mat[4] * mat[1] * mat[14] * mat[11] + mat[4] * mat[9] * mat[2] * mat[15] + mat[4] * mat[13] * mat[10] * mat[3] +
 
  138            mat[8] * mat[1] * mat[6] * mat[15] + mat[8] * mat[5] * mat[14] * mat[3] + mat[8] * mat[13] * mat[2] * mat[7] +
 
  139            mat[12] * mat[1] * mat[10] * mat[7] + mat[12] * mat[5] * mat[2] * mat[11] + mat[12] * mat[9] * mat[6] * mat[3] -
 
  140            mat[0] * mat[5] * mat[14] * mat[11] - mat[0] * mat[9] * mat[6] * mat[15] - mat[0] * mat[13] * mat[10] * mat[7] -
 
  141            mat[4] * mat[1] * mat[10] * mat[15] - mat[4] * mat[9] * mat[14] * mat[3] - mat[4] * mat[13] * mat[2] * mat[11] -
 
  142            mat[8] * mat[1] * mat[14] * mat[7] - mat[8] * mat[5] * mat[2] * mat[15] - mat[8] * mat[13] * mat[6] * mat[3] -
 
  143            mat[12] * mat[1] * mat[6] * mat[11] - mat[12] * mat[5] * mat[10] * mat[3] - mat[12] * mat[9] * mat[2] * mat[7];
 
  145   static bool inv_3by3(
double *
inv, 
const double *mat) {
 
  146     double det = det_3by3(mat);
 
  147     if((0 == det) || (0 == isfinite(det))) {
 
  148       memset(inv, 0, 9 * 
sizeof(*inv));
 
  151     inv[0] = (mat[4] * mat[8] - mat[5] * mat[7]) / det;
 
  152     inv[1] = (mat[2] * mat[7] - mat[1] * mat[8]) / det;
 
  153     inv[2] = (mat[1] * mat[5] - mat[2] * mat[4]) / det;
 
  154     inv[3] = (mat[5] * mat[6] - mat[3] * mat[8]) / det;
 
  155     inv[4] = (mat[0] * mat[8] - mat[2] * mat[6]) / det;
 
  156     inv[5] = (mat[2] * mat[3] - mat[0] * mat[5]) / det;
 
  157     inv[6] = (mat[3] * mat[7] - mat[4] * mat[6]) / det;
 
  158     inv[7] = (mat[1] * mat[6] - mat[0] * mat[7]) / det;
 
  159     inv[8] = (mat[0] * mat[4] - mat[1] * mat[3]) / det;
 
  163   static bool test_noncoplanar(
const Point *bs_pos, 
int bs_pos_len) {
 
  165     double *coord[] = {NULL, NULL};
 
  169     if((NULL == bs_pos) || (4 != bs_pos_len)) {
 
  174     coord[0] = (
double*)bs_pos;
 
  175     for(i = 0; i < 3; ++i) {
 
  176       coord[1] = (
double*)(bs_pos + i + 1);
 
  177       for(j = 0; j < 3; ++j) {
 
  178         mat[i + 3 * j] = (*(coord[1] + j)) - (*(coord[0] + j));
 
  181     return (0 != det_3by3(mat)) ? 
true : 
false;
 
  183   static bool combination(
unsigned int *comb_mat, 
unsigned int *nb_cols, 
unsigned int nb_rows, 
unsigned int len) {
 
  184     unsigned int idx = 0;
 
  185     unsigned int j, k, l, m;
 
  187     if((NULL == comb_mat) || (NULL == nb_cols)) {
 
  198       for(j = 1; j < len; ++j) {
 
  199         for(k = j + 1; k < len; ++k) {
 
  200           for(l = k + 1; l < len; ++l) {
 
  201             for(m = l + 1; m < len; ++m) {
 
  214       for(j = 1; j < len; ++j) {
 
  215         for(k = j + 1; k < len; ++k) {
 
  216           for(l = k + 1; l < len; ++l) {
 
  227       for(j = 1; j < len; ++j) {
 
  228         for(k = j + 1; k < len; ++k) {
 
  237       for(j = 1; j < len; ++j) {
 
  248     *nb_cols = idx / nb_rows;
 
  251   static unsigned int comb_nb(
unsigned int n, 
unsigned int k) {
 
  253     unsigned int nom = 1;
 
  254     unsigned int denom = 1;
 
  256     for(i = k + 1; i <= n; ++i) {
 
  260     for(i = 2; i <= (n - k); ++i) {
 
  265   static bool update_subsets(IndexSet &used_subset_idx, IndexSet &unused_subset_idx,
 
  266                              const unsigned int *subset_idx, 
unsigned int subset_idx_len) {
 
  269     for(i = 0; i < subset_idx_len; ++i) {
 
  270       if((
true == used_subset_idx.insert(subset_idx[i])) &&
 
  271           (
false == unused_subset_idx.remove(subset_idx[i]))) {
 
  279   static bool store_subset(
unsigned int **subsets, 
unsigned int *in_subset, 
unsigned int in_subset_len, 
unsigned int in_subset_idx) {
 
  283     *subsets = (
unsigned int*)realloc(*subsets, (in_subset_idx + 1) * in_subset_len * 
sizeof(**subsets));
 
  284     if(NULL != *subsets) {
 
  286       memcpy((*subsets) + in_subset_idx * in_subset_len, in_subset, in_subset_len * 
sizeof(*in_subset));
 
  300   enum GeoPos {GEO_POS_NO = 0, GEO_POS_YES, GEO_POS_EXACT};
 
  301   virtual GeoPos validate(
const Point *bs_pos, 
unsigned int bs_pos_len, 
const double *r) = 0;
 
  302   virtual bool setup(
const Point *bs_pos, 
unsigned int bs_pos_len) = 0;
 
  304   virtual bool get_pos(Point *ms_pos, 
const double *range, 
unsigned int range_len) = 0;
 
  305   virtual void set_meas_mat(
const double *meas) = 0;
 
  306   virtual void get_meas(
double *meas, 
const unsigned int *bs_subset_idx, 
unsigned int len) = 0;
 
  307   virtual bool get_meas_mult_mat(
const unsigned int *bs_pos_idx, 
unsigned int rows, 
unsigned int cols) = 0;
 
  308   virtual void get_meas_mult(
unsigned int *meas_mult, 
const unsigned int *subset_idx, 
unsigned int meas_mult_len) = 0;
 
  309   virtual bool get_grad(
double *grad, 
const Point *bs_pos, 
unsigned int bs_nb, 
const Point *ms_pos) = 0;
 
  310   virtual double* get_meas_mat() 
const = 0;
 
  311   virtual unsigned int* get_mult_mat() 
const = 0;
 
  312   virtual ~Algorithm() {}
 
  315 class Spherical : 
public Algorithm
 
  318   explicit Spherical(
unsigned int nb_bs);
 
  319   virtual ~Spherical();
 
  320   virtual Algorithm::GeoPos validate(
const Point *bs_pos, 
unsigned int bs_pos_len, 
const double *r);
 
  321   virtual bool setup(
const Point *bs_pos, 
unsigned int bs_pos_len);
 
  322   virtual bool get_pos(Point *ms_pos, 
const double *range, 
unsigned int range_len);
 
  323   virtual void set_meas_mat(
const double *meas) {
 
  324     memcpy(meas_mat_, meas, nb_bs_ * 
sizeof(*meas));
 
  326   virtual void get_meas(
double *meas, 
const unsigned int *bs_subset_idx, 
unsigned int len);
 
  327   virtual bool get_meas_mult_mat(
const unsigned int *bs_pos_idx, 
unsigned int rows, 
unsigned int cols);
 
  328   virtual void get_meas_mult(
unsigned int *meas_mult, 
const unsigned int *subset_idx, 
unsigned int meas_mult_len);
 
  329   virtual bool get_grad(
double *grad, 
const Point *bs_pos, 
unsigned int bs_nb, 
const Point *ms_pos);
 
  330   virtual double* get_meas_mat()
 const {
 
  333   virtual unsigned int* get_mult_mat()
 const {
 
  337   double mult_vTMw(
double v[2], 
double M[4], 
double w[2]) {
 
  338     return w[0] * (M[0] * v[0] + M[1] * v[1]) + w[1] * (M[2] * v[0] + M[3] * v[1]);
 
  340   double comp_quadratic(
double *u, 
const double *range) {
 
  346     v[1] = u[1] = range[0] * range[0];
 
  347     v[2] = u[2] = range[1] * range[1];
 
  348     v[3] = u[3] = range[2] * range[2];
 
  358     scalar = xi[0] * v[0];
 
  359     for(i = 1; i < 10; ++i) {
 
  360       scalar += xi[i] * v[i];
 
  366   unsigned int bs_pos_len_;
 
  373   unsigned int *mult_mat_;
 
  376 Spherical::Spherical(
unsigned int nb_bs) :
 
  378   meas_mat_(new double[nb_bs]),
 
  379   mult_mat_(new unsigned int [nb_bs])
 
  383 Spherical::~Spherical()
 
  390 Algorithm::GeoPos Spherical::validate(
const Point *bs_pos, 
unsigned int bs_pos_len, 
const double *r)
 
  392   GeoPos out = GEO_POS_NO;
 
  398   if(
true == Spherical::setup(bs_pos, bs_pos_len)) {
 
  400     double scalar = comp_quadratic(u, r);
 
  404     else if((0 < scalar) && (1 == bs_pos_len_)) {
 
  414 bool Spherical::setup(
const Point *bs_pos, 
unsigned int bs_pos_len)
 
  436   memset(xi, 0, 
sizeof(xi));
 
  437   memset(Lambda, 0, 
sizeof(Lambda));
 
  438   memset(mu, 0, 
sizeof(mu));
 
  441   for(i = 0; i < 3; ++i) {
 
  442     S[i] = bs_pos[i].x * bs_pos[i].x + bs_pos[i].y * bs_pos[i].y + bs_pos[i].z * bs_pos[i].z;
 
  444   W[0] = bs_pos[1].x - bs_pos[0].x;
 
  445   W[1] = bs_pos[2].x - bs_pos[0].x;
 
  446   W[2] = bs_pos[1].y - bs_pos[0].y;
 
  447   W[3] = bs_pos[2].y - bs_pos[0].y;
 
  448   detW = W[0] * W[3] - W[1] * W[2];
 
  453   invW[0] = W[3] / detW;
 
  454   invW[1] = -W[1] / detW;
 
  455   invW[2] = -W[2] / detW;
 
  456   invW[3] = W[0] / detW;
 
  457   G[0] = invW[0] * invW[0] + invW[1] * invW[1];
 
  458   G[1] = invW[0] * invW[2] + invW[1] * invW[3];
 
  460   G[3] = invW[2] * invW[2] + invW[3] * invW[3];
 
  461   rh1[0] = bs_pos[0].x;
 
  462   rh1[1] = bs_pos[0].y;
 
  463   for(i = 0; i < 2; ++i) {
 
  464     d[i] = bs_pos[i + 1].z - bs_pos[0].z;
 
  465     delta[i] = S[0] - S[i + 1];
 
  467   for(i = 0; i < 2; ++i) {
 
  468     e[i] = 0.5 * (delta[0] * G[2 * i] + delta[1] * G[2 * i + 1]) + rh1[0] * invW[2 * i] + rh1[1] * invW[2 * i + 1];
 
  470   a = 1.0 + mult_vTMw(d, G, d);
 
  472   lambda[0] = -(2 * mult_vTMw(rh1, invW, d) - 2 * bs_pos[0].z + mult_vTMw(d, G, delta)) / (2 * a);
 
  473   lambda[1] = ((bs_pos[1].z - bs_pos[0].z) * (G[0] + G[1]) + (bs_pos[2].z - bs_pos[0].z) * (G[1] + G[3])) / (2 * a);
 
  474   lambda[2] = -((bs_pos[1].z - bs_pos[0].z) * G[0] + (bs_pos[2].z - bs_pos[0].z) * G[1]) / (2 * a);
 
  475   lambda[3] = -((bs_pos[2].z - bs_pos[0].z) * G[3] + (bs_pos[1].z - bs_pos[0].z) * G[1]) / (2 * a);
 
  477   xi[0] = lambda[0] * lambda[0] - (0.25 * mult_vTMw(delta, G, delta) + mult_vTMw(rh1, invW, delta) + S[0]) / a;
 
  478   xi[1] = 2 * lambda[0] * lambda[1] + (1 + e[0] + e[1]) / a;
 
  479   xi[2] = 2 * lambda[0] * lambda[2] - e[0] / a;
 
  480   xi[3] = 2 * lambda[0] * lambda[3] - e[1] / a;
 
  481   xi[4] = lambda[1] * lambda[1] - (G[0] + 2 * G[1] + G[3]) / (4 * a);
 
  482   xi[5] = lambda[2] * lambda[2] - G[0] / (4 * a);
 
  483   xi[6] = lambda[3] * lambda[3] - G[3] / (4 * a);
 
  484   xi[7] = 2 * lambda[1] * lambda[2] + (G[0] + G[1]) / (2 * a);
 
  485   xi[8] = 2 * lambda[1] * lambda[3] + (G[1] + G[3]) / (2 * a);
 
  486   xi[9] = 2 * lambda[2] * lambda[3] - G[1] / (2 * a);
 
  488   w1Td = invW[0] * d[0] + invW[2] * d[1];
 
  489   w2Td = invW[1] * d[0] + invW[3] * d[1];
 
  491   Lambda[0] = -w1Td * lambda[0] - (invW[0] * delta[0] + invW[2] * delta[1]) / 2;
 
  492   Lambda[3] = -w1Td * lambda[1] + (bs_pos[2].y - bs_pos[1].y) / (2 * detW);
 
  493   Lambda[6] = -w1Td * lambda[2] - (bs_pos[2].y - bs_pos[0].y) / (2 * detW);
 
  494   Lambda[9] = -w1Td * lambda[3] + (bs_pos[1].y - bs_pos[0].y) / (2 * detW);
 
  496   Lambda[1] = -w2Td * lambda[0] - (invW[1] * delta[0] + invW[3] * delta[1]) / 2;
 
  497   Lambda[4] = -w2Td * lambda[1] + (bs_pos[1].x - bs_pos[2].x) / (2 * detW);
 
  498   Lambda[7] = -w2Td * lambda[2] + (bs_pos[2].x - bs_pos[0].x) / (2 * detW);
 
  499   Lambda[10] = -w2Td * lambda[3] - (bs_pos[1].x - bs_pos[0].x) / (2 * detW);
 
  501   Lambda[2] = lambda[0];
 
  502   Lambda[5] = lambda[1];
 
  503   Lambda[8] = lambda[2];
 
  504   Lambda[11] = lambda[3];
 
  514   if(4 == bs_pos_len) {
 
  515     if(
false == PosHelper::test_noncoplanar(bs_pos, bs_pos_len)) {
 
  526 bool Spherical::get_pos(Point *ms_pos, 
const double *range, 
unsigned int range_len)
 
  532   double *coord = NULL;
 
  535     it_warning(
"at least 3 measurements are needed");
 
  538   if(0 == bs_pos_len_) {
 
  539     it_warning(
"geo_spheric_setup needs to be called first");
 
  543   scalar = comp_quadratic(u, range);
 
  545     it_warning(
"square root from negative number");
 
  553   coord = (
double*)ms_pos;
 
  554   for(j = 0; j < 3; ++j) {
 
  555     coord[j] = mu[j] * scalar;
 
  556     for(i = 0; i < 4; ++i) {
 
  557       coord[j] += Lambda[3 * i + j] * u[i];
 
  566     coord = (
double*)(&tmp_pos);
 
  567     for(j = 0; j < 3; ++j) {
 
  568       coord[j] = mu[3 + j] * scalar;
 
  569       for(i = 0; i < 4; ++i) {
 
  570         coord[j] += Lambda[3 * i + j] * u[i];
 
  574     r1[0] = fabs(PosHelper::get_dist(ms_pos, &bs_pos_) - range[3]);
 
  575     r1[1] = fabs(PosHelper::get_dist(&tmp_pos, &bs_pos_) - range[3]);
 
  584 void Spherical::get_meas(
double *meas, 
const unsigned int *bs_subset_idx, 
unsigned int len)
 
  587   for(i = 0; i < len; ++i) {
 
  588     meas[i] = meas_mat_[bs_subset_idx[i]];
 
  592 bool Spherical::get_meas_mult_mat(
const unsigned int *bs_pos_idx, 
unsigned int rows, 
unsigned int cols)
 
  594   memset(mult_mat_, 0, nb_bs_ * 
sizeof(*mult_mat_));
 
  599   for(
unsigned int i = 0; i < (rows * cols); ++i) {
 
  600     if(nb_bs_ <= bs_pos_idx[i]) {
 
  603     ++mult_mat_[bs_pos_idx[i]];
 
  608 void Spherical::get_meas_mult(
unsigned int *meas_mult, 
const unsigned int *subset_idx, 
unsigned int meas_mult_len)
 
  610   for(
unsigned int i = 0; i < meas_mult_len; ++i) {
 
  611     meas_mult[i] = mult_mat_[subset_idx[i]];
 
  615 bool Spherical::get_grad(
double *grad, 
const Point *bs_pos, 
unsigned int bs_nb, 
const Point *ms_pos)
 
  617   double *coord_ms = NULL;
 
  618   double *coord_bs = NULL;
 
  623   coord_ms = (
double*)ms_pos;
 
  624   for(n = 0; n < bs_nb; ++n) {
 
  625     denom = PosHelper::get_dist(ms_pos, bs_pos + n);
 
  630     coord_bs = (
double*)(bs_pos + n); 
 
  631     for(i = 0; i < 3; ++i) {
 
  632       grad[i + 3 * n] = (coord_ms[i] - coord_bs[i]) / denom;
 
  638 class Hyperbolic : 
public Algorithm
 
  641   explicit Hyperbolic(
unsigned int nb_bs);
 
  642   virtual ~Hyperbolic();
 
  643   virtual Algorithm::GeoPos validate(
const Point *bs_pos, 
unsigned int bs_pos_len, 
const double *r);
 
  644   virtual bool setup(
const Point *bs_pos, 
unsigned int bs_pos_len);
 
  645   virtual bool get_pos(Point *ms_pos, 
const double *range, 
unsigned int range_len);
 
  646   virtual void set_meas_mat(
const double *meas) {
 
  647     memcpy(meas_mat_, meas, nb_bs_ * nb_bs_ * 
sizeof(*meas));
 
  649   virtual void get_meas(
double *meas, 
const unsigned int *bs_subset_idx, 
unsigned int len);
 
  650   virtual bool get_meas_mult_mat(
const unsigned int *bs_pos_idx, 
unsigned int rows, 
unsigned int cols);
 
  651   virtual void get_meas_mult(
unsigned int *meas_mult, 
const unsigned int *subset_idx, 
unsigned int meas_mult_len);
 
  652   virtual bool get_grad(
double *grad, 
const Point *bs_pos, 
unsigned int bs_nb, 
const Point *ms_pos);
 
  653   virtual double* get_meas_mat()
 const {
 
  656   virtual unsigned int* get_mult_mat()
 const {
 
  660   double dot_prod(
const double *v, 
const double *w, 
int len) {
 
  661     double out = v[0] * w[0];
 
  663     for(i = 1; i < len; ++i) {
 
  668   char comp_quadratic(
double *c, 
double *r1, 
double *beta, 
const double *r) {
 
  669     double diff_range2[3];
 
  677     for(i = 0; i < 3; ++i) {
 
  678       diff_range2[i] = r[i] * r[i];
 
  680     coord = (
double*)(bs_pos_);
 
  681     for(i = 0; i < 3; ++i) {
 
  682       c[i] = b[i] - 0.5 * dot_prod(A + 3 * i, diff_range2, 3);
 
  683       alpha[i] = coord[i] - c[i];
 
  684       beta[i] = dot_prod(A + 3 * i, r, 3);
 
  690     for(i = 0; i < 3; ++i) {
 
  691       d += beta[i] * beta[i];
 
  692       e += 2 * alpha[i] * beta[i];
 
  693       f += alpha[i] * alpha[i];
 
  695     delta = e * e - 4 * d * f;
 
  705     r1[0] = (-e + 
std::sqrt(delta)) / (2 * d);
 
  706     r1[1] = (-e - 
std::sqrt(delta)) / (2 * d);
 
  714   unsigned int bs_pos_len_;
 
  717   unsigned int *mult_mat_;
 
  721 Hyperbolic::Hyperbolic(
unsigned int nb_bs) :
 
  723   meas_mat_(new double[nb_bs*nb_bs]),
 
  724   mult_mat_(new unsigned int[nb_bs*nb_bs])
 
  728 Hyperbolic::~Hyperbolic()
 
  734 bool Hyperbolic::setup(
const Point *bs_pos, 
unsigned int bs_pos_len)
 
  741   if((4 > bs_pos_len) || (NULL == bs_pos)) {
 
  746   memset(b, 0, 
sizeof(b));
 
  747   memset(A, 0, 
sizeof(A));
 
  748   memset(bs_pos_, 0, 
sizeof(bs_pos_));
 
  751   for(i = 0; i < 3; ++i) {
 
  752     tmp[i] = bs_pos[i + 1].x - bs_pos[0].x;
 
  753     tmp[i + 3] = bs_pos[i + 1].y - bs_pos[0].y;
 
  754     tmp[i + 2 * 3] = bs_pos[i + 1].z - bs_pos[0].z;
 
  756   if(
false == PosHelper::inv_3by3(A, tmp)) {
 
  761   for(i = 0; i < 3; ++i) {
 
  763     tmp[3 * i + 1] = A[3 + i];
 
  764     tmp[3 * i + 2] = A[6 + i];
 
  766   memcpy(A, tmp, 
sizeof(A));
 
  768   K0 = bs_pos[0].x * bs_pos[0].x + bs_pos[0].y * bs_pos[0].y + bs_pos[0].z * bs_pos[0].z;
 
  769   for(i = 0; i < 3; ++i) {
 
  770     K[i] = bs_pos[i + 1].x * bs_pos[i + 1].x + bs_pos[i + 1].y * bs_pos[i + 1].y + bs_pos[i + 1].z * bs_pos[i + 1].z - K0;
 
  772   for(i = 0; i < 3; ++i) {
 
  773     b[i] = 0.5 * dot_prod(A + 3 * i, K, 3);
 
  776   memcpy(bs_pos_, bs_pos, 
sizeof(bs_pos_[0]));
 
  778   if(5 == bs_pos_len) {
 
  781     if(
false == PosHelper::test_uniqueness(bs_pos, bs_pos_len, 1e-3)) {
 
  785     memcpy(bs_pos_ + 1, bs_pos + 4, 
sizeof(bs_pos_[1]));
 
  792 Algorithm::GeoPos Hyperbolic::validate(
const Point *bs_pos, 
unsigned int bs_pos_len, 
const double *r)
 
  797   Algorithm::GeoPos out = GEO_POS_NO;
 
  800   if((NULL == bs_pos) || (0 == bs_pos_len) || (NULL == r)) {
 
  805   if(
true == setup(bs_pos, bs_pos_len)) {
 
  808     delta_sign = comp_quadratic(c, r1, beta, r);
 
  811     if(0 == delta_sign) {
 
  815     else if((0 < delta_sign) && (2 == bs_pos_len_)) {
 
  820       for(i = 0; i < 4; ++i) {
 
  821         tmp[i] = bs_pos[i + 1].x - bs_pos[0].x;
 
  822         tmp[4 + i] = bs_pos[i + 1].y - bs_pos[0].y;
 
  823         tmp[2 * 4 + i] = bs_pos[i + 1].z - bs_pos[0].z;
 
  824         tmp[3 * 4 + i] = r[i];
 
  826       det = PosHelper::det_4by4(tmp);
 
  827       out = (0 != 
det) ? GEO_POS_YES : GEO_POS_NO;
 
  833 bool Hyperbolic::get_pos(Point *ms_pos, 
const double *r, 
unsigned int r_len)
 
  842   if((3 > r_len) || (NULL == r)) {
 
  843     it_warning(
"at least 3 measurements are needed");
 
  850   if(0 == bs_pos_len_) {
 
  851     it_warning(
"geo_hyper_setup needs to be called first");
 
  856   delta_sign = comp_quadratic(c, r1, beta, r);
 
  859   if(0 == delta_sign) {
 
  861     coord = (
double*)(ms_pos);
 
  862     for(j = 0; j < 3; ++j) {
 
  863       coord[j] = c[j] - beta[j] * r1[0];
 
  869     if((4 != r_len) || (2 != bs_pos_len_)) {
 
  870       it_warning(
"4 measurements from 5 BSs are needed");
 
  874     for(i = 0; i < 2; ++i) {
 
  875       coord = (
double*)(out + i);
 
  876       for(j = 0; j < 3; ++j) {
 
  877         coord[j] = c[j] - beta[j] * r1[i];
 
  881     for(i = 0; i < 2; ++i) {
 
  882       r1[i] = PosHelper::get_dist(bs_pos_ + 1, out + i) - PosHelper::get_dist(bs_pos_, out + i);
 
  883       r1[i] = fabs(r1[i] - r[3]);
 
  888     memcpy(ms_pos, out + j, 
sizeof(*ms_pos));
 
  893 void Hyperbolic::get_meas(
double *meas, 
const unsigned int *bs_subset_idx, 
unsigned int len)
 
  895   for(
unsigned int i = 0; i < (len - 1); ++i) {
 
  896     meas[i] = meas_mat_[bs_subset_idx[i + 1] + nb_bs_ * bs_subset_idx[0]];
 
  900 bool Hyperbolic::get_meas_mult_mat(
const unsigned int *bs_pos_idx, 
unsigned int rows, 
unsigned int cols)
 
  904   memset(mult_mat_, 0, nb_bs_ * nb_bs_ * 
sizeof(*mult_mat_));
 
  909   for(j = 0; j < cols; ++j) {
 
  910     if(nb_bs_ <= bs_pos_idx[rows * j]) {
 
  913     for(i = 0; i < (rows - 1); ++i) {
 
  914       if(nb_bs_ <= bs_pos_idx[i + 1 + rows * j]) {
 
  917       ++mult_mat_[bs_pos_idx[i + 1 + rows * j] + nb_bs_ * bs_pos_idx[rows * j]];
 
  923 void Hyperbolic::get_meas_mult(
unsigned int *meas_mult, 
const unsigned int *subset_idx, 
unsigned int meas_mult_len)
 
  925   for(
unsigned int i = 0; i < meas_mult_len; ++i) {
 
  926     meas_mult[i] = mult_mat_[subset_idx[i + 1] + nb_bs_ * subset_idx[0]];
 
  934 bool Hyperbolic::get_grad(
double *grad, 
const Point *bs_pos, 
unsigned int bs_nb, 
const Point *ms_pos)
 
  937   double *coord_ms = NULL;
 
  938   double *coord_bs = NULL;
 
  943   denom = PosHelper::get_dist(ms_pos, bs_pos);
 
  948   coord_ms = (
double*)ms_pos;
 
  949   coord_bs = (
double*)bs_pos;
 
  950   for(i = 0; i < 3; ++i) {
 
  951     dr[i] = (coord_ms[i] - coord_bs[i]) / denom;
 
  953   for(n = 1; n < bs_nb; ++n) {
 
  954     denom = PosHelper::get_dist(ms_pos, bs_pos + n);
 
  959     coord_bs = (
double*)(bs_pos + n); 
 
  960     for(i = 0; i < 3; ++i) {
 
  961       grad[i + 3 * (n - 1)] = (coord_ms[i] - coord_bs[i]) / denom - dr[i];
 
  967 bool Multilateration::set_method(
const itpp::bvec &method)
 
  969   int method_len = 
length(method);
 
  975   if((0 == nb_bs_) || (4 > method_len)) {
 
  976     it_warning(
"BSs positions are not set or too small method length");
 
  982   for(n = 0; n < method_len; ++n) {
 
  983     if(bin(1) == method[n]) {
 
  987   if(n == method_len) {
 
  992   for(n = 0; n < method_len; ++n) {
 
  993     if(bin(0) == method[n]) {
 
  997   if(n == method_len) {
 
 1011     if((method_len + 1) != nb_bs_) {
 
 1012       it_warning(
"For hyperbolic multilateration the number of BSs should exceed by one the number of measures");
 
 1015     algo_ = 
new Hyperbolic(nb_bs_);
 
 1018     if((method_len + 1) != nb_bs_) {
 
 1019       it_warning(
"For hybrid multilateration the number of BSs should exceed by one the number of measures");
 
 1022     algo_ = 
new Spherical(nb_bs_ - 1); 
 
 1025     if(method_len != nb_bs_) {
 
 1026       it_warning(
"For spherical multilateration the number of BSs should equal the number of measures");
 
 1029     algo_ = 
new Spherical(nb_bs_);
 
 1032     it_warning(
"unknown multilateration method");
 
 1035   nb_fails_part = nb_fails_pos = 0;
 
 1037   return (NULL != algo_) ? 
true : 
false;
 
 1040 bool Multilateration::set_bs_pos(
const itpp::mat &bs_pos)
 
 1042   int rows = bs_pos.rows();
 
 1043   int cols = bs_pos.cols();
 
 1045   if(((3 != cols) && (3 != rows)) || (cols == rows)) {
 
 1046     it_warning(
"BS positions should be specified in 3D cartezian coordinates on either columns or rows");
 
 1049   nb_bs_ = (3 == cols) ? rows : cols;
 
 1050   if(NULL != bs_pos_) {
 
 1053   bs_pos_ = 
new Point[nb_bs_];
 
 1056     for(n = 0; n < nb_bs_; ++n) {
 
 1057       bs_pos_[n].x = bs_pos(n, 0);
 
 1058       bs_pos_[n].y = bs_pos(n, 1);
 
 1059       bs_pos_[n].z = bs_pos(n, 2);
 
 1062   else if(3 == rows) {
 
 1063     for(n = 0; n < nb_bs_; ++n) {
 
 1064       bs_pos_[n].x = bs_pos(0, n);
 
 1065       bs_pos_[n].y = bs_pos(1, n);
 
 1066       bs_pos_[n].z = bs_pos(2, n);
 
 1080   unsigned int *subsets_idx = NULL;
 
 1081   unsigned int subsets_nb = 0;
 
 1082   unsigned int subset_len = 0;
 
 1083   Point *tmp_bs_pos = NULL;
 
 1084   Point *bs_pos = bs_pos_;
 
 1085   unsigned int nb_bs = nb_bs_;
 
 1087   const int method_len = 
length(method_);
 
 1090   if((0 == method_len) || (NULL == bs_pos_) || (0 == nb_bs_) || (NULL == algo_)) {
 
 1094   algo_->set_meas_mat(measures);
 
 1101     tmp_bs_pos = (Point*)malloc(nb_bs_ * 
sizeof(*tmp_bs_pos));
 
 1102     memcpy(tmp_bs_pos, bs_pos_, nb_bs_ * 
sizeof(*tmp_bs_pos));
 
 1103     if(
false == hybrid2spherical(tmp_bs_pos, algo_->get_meas_mat())) {
 
 1106     bs_pos = tmp_bs_pos;
 
 1118   if((
false == partition(&subsets_idx, &subsets_nb, bs_pos, nb_bs, subset_len)) || (0 == subsets_nb)) {
 
 1121   if(0 != subsets_nb) {
 
 1122     if(
false == algo_->get_meas_mult_mat(subsets_idx, subset_len, subsets_nb)) {
 
 1125     if(
false == get_ml_pos(&tmp_ms_pos, bs_pos, nb_bs, subsets_idx, subsets_nb, subset_len)) {
 
 1130       ms_pos(0) = tmp_ms_pos.x;
 
 1131       ms_pos(1) = tmp_ms_pos.y;
 
 1132       ms_pos(2) = tmp_ms_pos.z;
 
 1136   out = (0 != subsets_nb) ? 
true : 
false;
 
 1140   if(NULL != subsets_idx) {
 
 1145   if(NULL != tmp_bs_pos) {
 
 1153 bool Multilateration::hybrid2spherical(Point *bs_pos, 
double *meas)
 
 1157   Point *out_bs_pos = NULL;
 
 1158   double *out_meas = NULL;
 
 1159   int method_len = 
length(method_);
 
 1160   static const bin zero = bin(0);
 
 1162   if((4 > method_len) || (NULL == bs_pos) || (NULL == meas)) {
 
 1171   for(n = 0; n < method_len; ++n) {
 
 1172     if(zero == method_[n]) {
 
 1176   if(n == method_len) {
 
 1180   out_bs_pos = (Point*)malloc(method_len * 
sizeof(*out_bs_pos));
 
 1181   if(NULL == out_bs_pos) {
 
 1184   out_meas = (
double*)malloc(method_len * 
sizeof(*out_meas));
 
 1185   if(NULL == out_meas) {
 
 1192     out_meas[0] = meas[0];
 
 1193     out_bs_pos[0] = bs_pos[0];
 
 1194     for(k = 1; k < method_len; ++k) {
 
 1195       if(zero == method_[k]) {
 
 1196         out_bs_pos[k] = bs_pos[k];
 
 1197         out_meas[k] = meas[k];
 
 1200         out_meas[k] = meas[k] + out_meas[0];
 
 1201         out_bs_pos[k] = bs_pos[k + 1];
 
 1209     out_meas[0] = meas[n] - meas[n - 1];
 
 1210     out_bs_pos[0] = bs_pos[0];
 
 1211     for(k = 0; k < method_len; ++k) {
 
 1215       if(zero == method_[k]) {
 
 1216         out_bs_pos[idx] = bs_pos[k];
 
 1217         out_meas[idx] = meas[k];
 
 1220         out_bs_pos[idx] = bs_pos[k + 1];
 
 1221         out_meas[idx] = meas[k] + out_meas[0];
 
 1228   for(k = 0; k < method_len; ++k) {
 
 1229     bs_pos[k] = out_bs_pos[k];
 
 1230     meas[k] = out_meas[k];
 
 1238 bool Multilateration::partition(
unsigned int **subsets_idx, 
unsigned int *subsets_nb, 
const Point *bs_pos, 
unsigned int nb_bs, 
unsigned int subset_len)
 
 1240   unsigned int nb_avail_bs = nb_bs;
 
 1241   unsigned int *comb_mat = NULL;
 
 1242   unsigned int nb_comb = 0;
 
 1246   Point bs_pos_subset[5];
 
 1247   unsigned int *bs_subset_idx = NULL;
 
 1249   char subset_found = 0;
 
 1250   int valid_res = Algorithm::GEO_POS_NO;
 
 1253   if((nb_avail_bs < subset_len) || (NULL == subsets_idx) || (NULL == subsets_nb) || (NULL == bs_pos)) {
 
 1257   *subsets_idx = NULL;
 
 1261   IndexSet unused_subset_idx(nb_avail_bs);
 
 1262   for(n = 0; n < nb_avail_bs; ++n) {
 
 1263     unused_subset_idx[n] = n;
 
 1265   unused_subset_idx.set_size(nb_avail_bs);
 
 1266   IndexSet used_subset_idx(nb_avail_bs);
 
 1267   nb_comb = PosHelper::comb_nb(nb_avail_bs - 1, subset_len - 1);
 
 1268   comb_mat = (
unsigned int*)malloc(subset_len * nb_comb * 
sizeof(*comb_mat));
 
 1269   if(NULL == comb_mat) {
 
 1273   bs_subset_idx = (
unsigned int*)malloc(subset_len * 
sizeof(*bs_subset_idx));
 
 1274   if(NULL == bs_subset_idx) {
 
 1282   while((0 != unused_subset_idx.get_size()) && (nb_avail_bs >= subset_len)) {
 
 1284     if(
false == PosHelper::combination(comb_mat, &nb_comb, subset_len, unused_subset_idx.get_size())) {
 
 1290     while(n < nb_comb) {
 
 1291       for(i = 0; i < subset_len; ++i) {
 
 1292         bs_subset_idx[i] = unused_subset_idx[comb_mat[i + n * subset_len]];
 
 1293         bs_pos_subset[i] = bs_pos[bs_subset_idx[i]];
 
 1295       algo_->get_meas(meas, bs_subset_idx, subset_len);
 
 1296       valid_res = algo_->validate(bs_pos_subset, subset_len, meas);
 
 1297       if((Algorithm::GEO_POS_EXACT == valid_res) || (Algorithm::GEO_POS_YES == valid_res)) {
 
 1299         if(
false == PosHelper::store_subset(subsets_idx, bs_subset_idx, subset_len, *subsets_nb)) {
 
 1305         if(
false == PosHelper::update_subsets(used_subset_idx, unused_subset_idx, bs_subset_idx, subset_len)) {
 
 1306           it_warning(
"error in geo_pos_update_subsets");
 
 1314         if(
false == PosHelper::combination(comb_mat, &nb_comb, subset_len, unused_subset_idx.get_size())) {
 
 1323     if((0 == unused_subset_idx.get_size()) || (
false == res)) {
 
 1329     if(
false == PosHelper::combination(comb_mat, &nb_comb, subset_len, nb_avail_bs)) {
 
 1334     for(n = 0; n < nb_comb; ++n) {
 
 1335       if(comb_mat[subset_len - 1 + subset_len * n] < unused_subset_idx[0]) { 
 
 1338       for(i = 0; i < subset_len; ++i) {
 
 1339         k = comb_mat[i + n * subset_len];
 
 1340         if(k < unused_subset_idx.get_size()) {
 
 1341           bs_subset_idx[i] = unused_subset_idx[k];
 
 1345           bs_subset_idx[i] = used_subset_idx[used_subset_idx.get_size() - 1 - (k - unused_subset_idx.get_size())];
 
 1347         bs_pos_subset[i] = bs_pos[bs_subset_idx[i]];
 
 1349       algo_->get_meas(meas, bs_subset_idx, subset_len);
 
 1350       valid_res = algo_->validate(bs_pos_subset, subset_len, meas);
 
 1351       if((Algorithm::GEO_POS_EXACT == valid_res) || (Algorithm::GEO_POS_YES == valid_res)) {
 
 1353         if(
false == PosHelper::store_subset(subsets_idx, bs_subset_idx, subset_len, *subsets_nb)) {
 
 1359         if(
false == PosHelper::update_subsets(used_subset_idx, unused_subset_idx, bs_subset_idx, subset_len)) {
 
 1360           it_warning(
"error in geo_pos_update_subsets");
 
 1372     if((0 == unused_subset_idx.get_size()) || (
false == res)) {
 
 1377     if(0 == subset_found) {
 
 1380       if(
false == unused_subset_idx.remove(unused_subset_idx[0])) {
 
 1391   free(bs_subset_idx);
 
 1395 bool Multilateration::get_bs_pos_subset(Point *bs_pos_subset, 
const Point *bs_pos, 
unsigned int nb_bs, 
const unsigned int *subset_idx, 
unsigned int subset_len)
 
 1399   for(i = 0; i < subset_len; ++i) {
 
 1405     bs_pos_subset[i] = bs_pos[k];
 
 1410 bool Multilateration::get_ml_pos(Point *ms_pos, 
const Point *bs_pos, 
unsigned int nb_bs, 
const unsigned int *subsets_idx, 
unsigned int subsets_nb, 
unsigned int subset_len)
 
 1412   Point bs_pos_subset[5];
 
 1414   unsigned int meas_mult[4];
 
 1422   double *coord = NULL;
 
 1425   if((NULL == bs_pos) || (0 == nb_bs) || (NULL == subsets_idx) || (0 == subsets_nb) || (0 == subset_len) || (NULL == ms_pos)) {
 
 1430   if(1 != subsets_nb) {
 
 1431     memset(nom, 0, 
sizeof(nom));
 
 1432     memset(denom, 0, 
sizeof(denom));
 
 1435   for(n = 0; n < subsets_nb; ++n) {
 
 1437     if(
false == get_bs_pos_subset(bs_pos_subset, bs_pos, nb_bs, subsets_idx + n * subset_len, subset_len)) {
 
 1440     if(
false == algo_->setup(bs_pos_subset, subset_len)) {
 
 1444     algo_->get_meas(meas, subsets_idx + n * subset_len, subset_len);
 
 1445     if(
false == algo_->get_pos(ms_pos, meas, 4)) {
 
 1449     if(1 == subsets_nb) {
 
 1454     if(
false == algo_->get_grad(grad, bs_pos_subset, subset_len, ms_pos)) {
 
 1458     algo_->get_meas_mult(meas_mult, subsets_idx + n * subset_len, 4);
 
 1459     if(
false == prod(coeff, grad, meas_mult, 3, 4)) {
 
 1464     coord = (
double*)ms_pos;
 
 1465     for(k = 0; k < 3; ++k) {
 
 1466       for(i = 0; i < 3; ++i) {
 
 1467         nom[k] += coeff[k + 3 * i] * coord[i];
 
 1468         denom[k + 3 * i] += coeff[k + 3 * i];
 
 1473   if(
true == PosHelper::inv_3by3(coeff, denom)) {
 
 1474     coord = (
double*)ms_pos;
 
 1475     for(n = 0; n < 3; ++n) {
 
 1477       for(k = 0; k < 3; ++k) {
 
 1478         coord[n] += coeff[n + 3 * k] * nom[k];
 
 1488 bool Multilateration::prod(
double *out, 
const double *AT, 
const unsigned int *d, 
unsigned int cols, 
unsigned int rows)
 
 1494   if((NULL == out) || (NULL == AT) || (NULL == d) || (0 == cols) || (0 == rows)) {
 
 1499   for(i = 0; i < cols; ++i) {  
 
 1500     for(n = 0; n < cols; ++n) {  
 
 1501       out[i + cols * n] = 0.0;
 
 1502       for(k = 0; k < rows; ++k) {  
 
 1507         out[i + cols * n] += (AT[i + k * cols] / (double)d[k]) * AT[n + k * cols];
 
 1516   if((3 != 
length(ms_pos)) || (0 == nb_bs_)) {
 
 1525   pos_ref(0) = bs_pos_[0].x;
 
 1526   pos_ref(1) = bs_pos_[0].y;
 
 1527   pos_ref(2) = bs_pos_[0].z;
 
 1529   static const bin zero = 
bin(0);
 
 1530   const unsigned int method_len = 
length(method_);
 
 1531   mat dh(3, method_len);
 
 1535   for(n = 0; n < method_len; ++n) {
 
 1536     if(zero == method_(n)) {
 
 1537       pos(0) = bs_pos_[n].x;
 
 1538       pos(1) = bs_pos_[n].y;
 
 1539       pos(2) = bs_pos_[n].z;
 
 1540       for(i = 0; i < 3; ++i) {
 
 1545       pos(0) = bs_pos_[n + 1].x;
 
 1546       pos(1) = bs_pos_[n + 1].y;
 
 1547       pos(2) = bs_pos_[n + 1].z;
 
 1548       for(i = 0; i < 3; ++i) {
 
 1556   for(n = 0; n < 3; ++n) {
 
 1557     for(i = 0; i < 3; ++i) {
 
 1558       info_mat(n, i) = dh.get_row(n) * dh.get_row(i);
 
 1561   info_mat = info_mat / sigma2;