// Gnurbs - A curve and surface library
// Copyright (C) 2008-2026 Eric Bechet
//
// See the LICENSE file for contributions and license information.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//

#ifndef _POINT_SET_H
#define _POINT_SET_H

#include <vector>
#include <string>
#include "nbspline.h"
#include "nutil.h"
#include "ANN.h"

class scanpt : public npoint3
{
  public :
  virtual ~scanpt() {}
  scanpt() : npoint3(0.,0.,0.),err(0.,0.,0.),clr(255,255,255) {}
  scanpt(npoint3 pt_,npoint3 err_,color clr_) : npoint3(pt_),err(err_),clr(clr_) {}
  npoint3 err;
  color clr;
};

struct dist_info
{
  int ndx;
  double distance;
  dist_info(int ndx_,double dist_) : ndx(ndx_),distance(dist_) {}
  bool operator <(const dist_info & other)
  {
    if (distance < other.distance) return true;
    if (distance > other.distance) return false;
    if (ndx < other.ndx) return true;
    return false;
  }
};

class PointSet
{
  std::vector<scanpt> pts;
  std::vector<double> param;
  double minp;
  double maxp;
  std::vector<double> distance;
  std::vector<int> sign;
  std::vector<double> density;
  ANNpointArray       dataPts;                // data points
  ANNkd_tree*         kdTree;                 // search structure
public:
  PointSet(size_t n=0): minp(0.0),maxp(1.0) {if(n) {pts.reserve(n);param.reserve(n);distance.reserve(n);sign.reserve(n);density.reserve(n);}}
  size_t size(void) const { return pts.size();}
  void resize(size_t i) {pts.resize(i);param.resize(i);distance.resize(i);sign.resize(i);density.resize(i);}
  void reserve(size_t i) {pts.reserve(i);param.reserve(i);distance.reserve(i);sign.resize(i);density.resize(i);}
  void clear() {pts.clear();param.clear();distance.clear();sign.clear();density.clear();}
  scanpt & operator[](size_t i) {return pts[i];}
  scanpt operator[](size_t i) const {return pts[i];}
  void read(std::string fname, bool coords_only=false);
  void read_gz(std::string fname, bool coords_only=false);
  void read_bin(std::string fname, int skip=1);
  void read_bin_gz(std::string fname, int skip=1);
  void write_bin(std::string fname) const ; //  points only (no param)
  void bbox(npoint3 &min,npoint3 &max) const;
  double & u(size_t i) {return param[i];}
  double u(size_t i) const {return param[i];}
  void insert(scanpt n) {pts.push_back(n);param.push_back(0.);distance.push_back(-1.);sign.push_back(0);density.push_back(0);}
  void translate(bool autotranslate, double &X, double & Y, double &Z);
  void filter(PointSet &dest,double Zplan,double DeltaZplan) const ;
  void filterX(PointSet &dest,double Xplan) const ;
  void initANN();
  void clearANN();
  double findkclosest(int i,std::vector<int> &closest, int k,double dist=0.0);
  double findkclosest(npoint3 pt,std::vector<int> &closest, int k,double dist=0.0);
  void compute_parameters();
  void filter_highest_density();
  int init_sign();
  void least_squares_bspline(int d,int nCP,nbspline &crv) const ;
  void Display(data_container & data, const int sample=1) const ;
};

#endif // _POINT_SET_H
