<commit_before>#ifndef G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_
#define G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_

/*===========================================================================*\

author: Matthias W. Smith
email:  mwsmith2@uw.edu
file:   field_constants.hh

about:  A header file for constant parameters used across field team
        software.

\*===========================================================================*/

//--- project includes  -----------------------------------------------------//
#include <vector>

//--- project includes  -----------------------------------------------------//
#include "field_constants.hh"

namespace g2field {

// A macro to define nmr structs since they are very similar.
#define MAKE_NMR_STRUCT(name, num_ch, len_tr)\
struct name {\
  Double_t sys_clock[num_ch];\
  Double_t gps_clock[num_ch];\
  Double_t dev_clock[num_ch];\
  Double_t snr[num_ch];\
  Double_t len[num_ch];\
  Double_t freq[num_ch];\
  Double_t ferr[num_ch];\
  Double_t freq_zc[num_ch];\
  Double_t ferr_zc[num_ch];\
  UShort_t health[num_ch];\
  UShort_t method[num_ch];\
  UShort_t trace[num_ch][len_tr];\
};

// Might as well define a root branch string for the struct.
#define MAKE_NMR_STRING(name, num_ch, len_tr) NMR_HELPER(name, num_ch, len_tr)

#define NMR_HELPER(name, num_ch, len_tr) \
const char * const name = "sys_clock["#num_ch"]/D:gps_clock["#num_ch"]/D:"\
"dev_clock["#num_ch"]/D:snr["#num_ch"]/D:len["#num_ch"]/D:freq["#num_ch"]/D:"\
"ferr["#num_ch"]/D:freq_zc["#num_ch"]/D:ferr_zc["#num_ch"]/D:"\
"health["#num_ch"]/s:method["#num_ch"]/s:trace["#num_ch"]["#len_tr"]/s"

// NMR structs
MAKE_NMR_STRUCT(fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);
MAKE_NMR_STRING(fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);

MAKE_NMR_STRUCT(online_fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);
MAKE_NMR_STRING(online_fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);

// Flexible struct built from the basic nmr attributes.
struct nmr_vector {
  std::vector<Double_t> sys_clock;
  std::vector<Double_t> gps_clock;
  std::vector<Double_t> dev_clock;
  std::vector<Double_t> snr;
  std::vector<Double_t> len;
  std::vector<Double_t> freq;
  std::vector<Double_t> ferr;
  std::vector<Double_t> freq_zc;
  std::vector<Double_t> ferr_zc;
  std::vector<UShort_t> health;
  std::vector<UShort_t> method;
  std::vector< std::array<UShort_t, NMR_FID_LENGTH_ONLINE> > trace;

  inline void Resize(int size) {
    sys_clock.resize(size);
    gps_clock.resize(size);
    dev_clock.resize(size);
    snr.resize(size);
    len.resize(size);
    freq.resize(size);
    ferr.resize(size);
    freq_zc.resize(size);
    ferr_zc.resize(size);
    health.resize(size);
    method.resize(size);
    trace.resize(size);
  }
};

//Trolley data structs
struct trolley_nmr_t{
  ULong64_t local_clock;
  UShort_t probe_index;
  UShort_t length;
  UShort_t TS_OffSet;
  UShort_t RF_Prescale;
  UShort_t Probe_Command;
  UShort_t Preamp_Delay;
  UShort_t Preamp_Period;
  UShort_t ADC_Gate_Delay;
  UShort_t ADC_Gate_Offset;
  UShort_t ADC_Gate_Period;
  UShort_t TX_On;
  UShort_t TX_Delay;
  UShort_t TX_Period;
  UShort_t UserDefinedData;
  Short_t trace[TRLY_NMR_LENGTH];
};

#define MAKE_TLNMR_STRING(len) HELPER_TLNMR_STRING(len)
#define HELPER_TLNMR_STRING(len) \
const char * const trolley_nmr_str = "local_clock/l:probe_index/s:len/s:TS_Offset/s:RF_Prescale/s:Probe_Command/s:Preamp_Delay/s:Preamp_Period/s:ADC_Gate_Delay/s:ADC_Gate_Offset/s:ADC_Gate_Period/s:TX_On/s:TX_Delay/s:TX_Period/s:UserDefinedData/s:trace["#len"]/S"
MAKE_TLNMR_STRING(TRLY_NMR_LENGTH);

struct trolley_barcode_t{
  ULong64_t local_clock;
  UShort_t length_per_ch;
  UShort_t Sampling_Period;
  UShort_t Acquisition_Delay;
  UShort_t DAC_1_Config;
  UShort_t DAC_2_Config;
  UShort_t Ref_CM;
  UShort_t traces[TRLY_BARCODE_LENGTH]; //All channels
};

#define MAKE_BARCODE_STRING(len) HELPER_BARCODE_STRING(len)
#define HELPER_BARCODE_STRING(len) \
const char * const trolley_barcode_str = "local_clock/l:len_per_ch/s:Sampling_Period/s:Acquisition_Delay/s:DAC_1_Config/s:DAC_2_Config/s:Ref_CM/s:traces["#len"]/s"
MAKE_BARCODE_STRING(TRLY_BARCODE_LENGTH);

struct trolley_monitor_t{
  ULong64_t local_clock_cycle_start;
  UInt_t PMonitorVal;
  UInt_t PMonitorTemp;
  UInt_t RFPower1;
  UInt_t RFPower2;
  UInt_t NMRCheckSum;
  UInt_t ConfigCheckSum;
  UInt_t FrameCheckSum;
  UInt_t NMRFrameSum;
  UInt_t ConfigFrameSum;
  UInt_t FrameSum;
  UInt_t FrameIndex;
  UShort_t StatusBits;
  UShort_t TMonitorIn;
  UShort_t TMonitorExt1;
  UShort_t TMonitorExt2;
  UShort_t TMonitorExt3;
  UShort_t V1Min;
  UShort_t V1Max;
  UShort_t V2Min;
  UShort_t V2Max;
  UShort_t length_per_ch;
  UShort_t Trolley_Command;
  UShort_t TIC_Stop;
  UShort_t TC_Start;
  UShort_t TD_Start;
  UShort_t TC_Stop;
  UShort_t Switch_RF;
  UShort_t PowerEnable;
  UShort_t RF_Enable;
  UShort_t Switch_Comm;
  UShort_t TIC_Start;
  UShort_t Cycle_Length;
  UShort_t Power_Control_1;
  UShort_t Power_Control_2;
  UShort_t trace_VMonitor1[TRLY_MONITOR_LENGTH];
  UShort_t trace_VMonitor2[TRLY_MONITOR_LENGTH];
};

#define MAKE_MONITOR_STRING(len) HELPER_MONITOR_STRING(len)
#define HELPER_MONITOR_STRING(len) \
const char * const trolley_monitor_str = "local_clock_cycle_start/l:PMonitorVal/i:PMonitorTemp/i:RFPower1/i:RFPower2/i:"\
"NMRCheckSum/i:ConfigCheckSum/i:FrameCheckSum/i:NMRFrameSum/i:ConfigFrameSum/i:FrameSum/i:FrameIndex/i:StatusBits/s:"\
"TMonitorIn/s:TMonitorExt1/s:TMonitorExt2/s:TMonitorExt3/s:V1Min/s:V1Max/s:V2Min/s:V2Max/s:len_per_ch/s:"\
"Trolley Command/s:TIC_Stop/s:TC_Start/s:TD_Start/s:TC_Stop/s:Switch_RF/s:PowerEnable/s:RF_Enable/s:"\
"Switch_Comm/s:TIC_Start/s:Cycle_Length/s:Power_Control_1/s:Power_Control_2/s:"\
"trace_VMonitor1["#len"]/s:trace_VMonitor2["#len"]/s"
MAKE_MONITOR_STRING(TRLY_MONITOR_LENGTH);

struct trolley_interface_t{
  ULong64_t gps_clock_cycle_start;
  ULong64_t local_clock_cycle_start;
  ULong64_t local_clock_iv;
  UInt_t rf_power0;
  UInt_t rf_power1;
  UShort_t rf_switch_offset;
  UShort_t comm_switch_offset;
  UShort_t n_iv_samples;
  UShort_t power_protection_trip;
  UShort_t power_status;
  UShort_t ldo_temp_monitor_min;
  UShort_t ldo_temp_monitor_max;
  UShort_t v_15neg_min;
  UShort_t v_15neg_max;
  UShort_t v_15pos_min;
  UShort_t v_15pos_max;
  UShort_t v_5_min;
  UShort_t v_5_max;
  UShort_t v_33_min;
  UShort_t v_33_max;
  UShort_t trace_v_monitor[TRLY_INTERFACE_MONITOR_LENGTH];
  UShort_t trace_i_monitor[TRLY_INTERFACE_MONITOR_LENGTH];
};

#define MAKE_INTERFACE_STRING(len) HELPER_INTERFACE_STRING(len)
#define HELPER_INTERFACE_STRING(len) \
const char * const trolley_interface_str = "gps_clock_cycle_start/l:local_clock_cycle_start/l:local_clock_iv/l:"\
"rf_power0/i:rf_power1/i:rf_switch_offset/s:comm_switch_offset/s:n_iv_samples/s:power_protection_trip/s:power_status/s:"\
"ldo_temp_monitor_min/s:ldo_temp_monitor_max/s:v_15neg_min/s:v_15neg_max/s:v_15pos_min/s:v_15pos_max/s:"\
"v_5_min/s:v_5_max/s:v_33_min/s:v_33_max/s:"\
"trace_v_monitor["#len"]/s:trace_i_monitor2["#len"]/s"
MAKE_INTERFACE_STRING(TRLY_INTERFACE_MONITOR_LENGTH);

struct trolley_extra_t{
  Double_t GalilTime;
  Int_t GalilPos[2];
  Int_t GalilVel[2];
};

#define MAKE_TRLYEXTRA_STRING() HELPER_TRLYEXTRA_STRING()
#define HELPER_TRLYEXTRA_STRING() \
const char * const trolley_extra_str = "GalilTIME/D:GalilPos[2]/I:GalilVel[2]/I"
MAKE_TRLYEXTRA_STRING();

//Galil Data structs
struct galil_trolley_t{
  ULong64_t TimeStamp;
  Int_t Tensions[2];
  Int_t Temperatures[2];
  Int_t Positions[3];
  Int_t Velocities[3];
  Int_t OutputVs[3];
};

const char * const galil_trolley_str = "TimeStamp/l:Tensions[2]/I:Temperatures[2]:Positions[3]/I:Velocities[3]/I:OutputVs[3]/I";

struct galil_plunging_probe_t{
  ULong64_t TimeStamp;
  Int_t Positions[3];
  Int_t Velocities[3];
  Int_t OutputVs[3];
};

const char * const galil_plunging_probe_str = "TimeStamp/l:Positions[3]/I:Velocities[3]/I:OutputVs[3]/I";

//Absolute probe data struct
struct absolute_nmr_info_t{
  ULong64_t time_stamp;
  UInt_t length;
  Int_t Pos[4]; //Coordinate X,Y,Z,S
  UShort_t flay_run_number;
  UShort_t probe_index;
  //Because the length of the trace varies too much, it is not included in this struct
};

#define MAKE_ABSNMR_STRING() HELPER_ABSNMR_STRING()
#define HELPER_ABSNMR_STRING() \
const char * const absolute_nmr_info_str = "time_stamp/l:length/i:Pos[4]/i:flay_run_number/s:probe_index/s"
MAKE_ABSNMR_STRING();

// Absolute calibration NMR structs
MAKE_NMR_STRUCT(abs_fixed_t, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);
MAKE_NMR_STRING(abs_fixed_str, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);

MAKE_NMR_STRUCT(abs_online_fixed_t, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);
MAKE_NMR_STRING(abs_online_fixed_str, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);

//Surface coil struct
struct surface_coil_t{
  Double_t bot_sys_clock[SC_NUM_COILS];
  Double_t top_sys_clock[SC_NUM_COILS];
  Double_t bot_coil_currents[SC_NUM_COILS];
  Double_t top_coil_currents[SC_NUM_COILS];
  Double_t bot_coil_temps[SC_NUM_COILS];
  Double_t top_coil_temps[SC_NUM_COILS];
};

#define MAKE_SC_STRING(name,num_coils) SC_HELPER(name,num_coils)

#define SC_HELPER(name,num_coils)\
const char * const name = "sys_clock["#num_coils"]/D:bot_coil_currents["#num_coils"]/D:top_coil_currents["#num_coils"]/D:bot_coil_temps["#num_coils"]/D:top_coil_temps["#num_coils"]/D"

MAKE_SC_STRING(sc_str,SC_NUM_COILS);

// Yokogawa struct
struct yokogawa_t{
   ULong64_t sys_clock;   // system clock
   ULong64_t gps_clock;   // GPS clock
   Int_t mode;            // device mode (0 = voltage, 1 = current)
   Int_t is_enabled;      // is the output enabled (0 = false, 1 = true)
   Double_t current;      // current setting (in mA)
   Double_t voltage;      // voltage setting (in V)
};

#define MAKE_YOKO_STRING() HELPER_YOKO_STRING()
#define HELPER_YOKO_STRING() \
const char * const yokogawa_str = "sys_clock/l:gps_clock/l:is_enabled/i:current/D"
MAKE_YOKO_STRING();

} // ::g2field

#endif
<commit_msg>adding trolley interface<commit_after>#ifndef G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_
#define G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_

/*===========================================================================*\

author: Matthias W. Smith
email:  mwsmith2@uw.edu
file:   field_constants.hh

about:  A header file for constant parameters used across field team
        software.

\*===========================================================================*/

//--- project includes  -----------------------------------------------------//
#include <vector>

//--- project includes  -----------------------------------------------------//
#include "field_constants.hh"

namespace g2field {

// A macro to define nmr structs since they are very similar.
#define MAKE_NMR_STRUCT(name, num_ch, len_tr)\
struct name {\
  Double_t sys_clock[num_ch];\
  Double_t gps_clock[num_ch];\
  Double_t dev_clock[num_ch];\
  Double_t snr[num_ch];\
  Double_t len[num_ch];\
  Double_t freq[num_ch];\
  Double_t ferr[num_ch];\
  Double_t freq_zc[num_ch];\
  Double_t ferr_zc[num_ch];\
  UShort_t health[num_ch];\
  UShort_t method[num_ch];\
  UShort_t trace[num_ch][len_tr];\
};

// Might as well define a root branch string for the struct.
#define MAKE_NMR_STRING(name, num_ch, len_tr) NMR_HELPER(name, num_ch, len_tr)

#define NMR_HELPER(name, num_ch, len_tr) \
const char * const name = "sys_clock["#num_ch"]/D:gps_clock["#num_ch"]/D:"\
"dev_clock["#num_ch"]/D:snr["#num_ch"]/D:len["#num_ch"]/D:freq["#num_ch"]/D:"\
"ferr["#num_ch"]/D:freq_zc["#num_ch"]/D:ferr_zc["#num_ch"]/D:"\
"health["#num_ch"]/s:method["#num_ch"]/s:trace["#num_ch"]["#len_tr"]/s"

// NMR structs
MAKE_NMR_STRUCT(fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);
MAKE_NMR_STRING(fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);

MAKE_NMR_STRUCT(online_fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);
MAKE_NMR_STRING(online_fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);

// Flexible struct built from the basic nmr attributes.
struct nmr_vector {
  std::vector<Double_t> sys_clock;
  std::vector<Double_t> gps_clock;
  std::vector<Double_t> dev_clock;
  std::vector<Double_t> snr;
  std::vector<Double_t> len;
  std::vector<Double_t> freq;
  std::vector<Double_t> ferr;
  std::vector<Double_t> freq_zc;
  std::vector<Double_t> ferr_zc;
  std::vector<UShort_t> health;
  std::vector<UShort_t> method;
  std::vector< std::array<UShort_t, NMR_FID_LENGTH_ONLINE> > trace;

  inline void Resize(int size) {
    sys_clock.resize(size);
    gps_clock.resize(size);
    dev_clock.resize(size);
    snr.resize(size);
    len.resize(size);
    freq.resize(size);
    ferr.resize(size);
    freq_zc.resize(size);
    ferr_zc.resize(size);
    health.resize(size);
    method.resize(size);
    trace.resize(size);
  }
};

//Trolley data structs
struct trolley_nmr_t{
  ULong64_t local_clock;
  UShort_t probe_index;
  UShort_t length;
  UShort_t TS_OffSet;
  UShort_t RF_Prescale;
  UShort_t Probe_Command;
  UShort_t Preamp_Delay;
  UShort_t Preamp_Period;
  UShort_t ADC_Gate_Delay;
  UShort_t ADC_Gate_Offset;
  UShort_t ADC_Gate_Period;
  UShort_t TX_On;
  UShort_t TX_Delay;
  UShort_t TX_Period;
  UShort_t UserDefinedData;
  Short_t trace[TRLY_NMR_LENGTH];
};

#define MAKE_TLNMR_STRING(len) HELPER_TLNMR_STRING(len)
#define HELPER_TLNMR_STRING(len) \
const char * const trolley_nmr_str = "local_clock/l:probe_index/s:len/s:TS_Offset/s:RF_Prescale/s:Probe_Command/s:Preamp_Delay/s:Preamp_Period/s:ADC_Gate_Delay/s:ADC_Gate_Offset/s:ADC_Gate_Period/s:TX_On/s:TX_Delay/s:TX_Period/s:UserDefinedData/s:trace["#len"]/S"
MAKE_TLNMR_STRING(TRLY_NMR_LENGTH);

struct trolley_barcode_t{
  ULong64_t local_clock;
  UShort_t length_per_ch;
  UShort_t Sampling_Period;
  UShort_t Acquisition_Delay;
  UShort_t DAC_1_Config;
  UShort_t DAC_2_Config;
  UShort_t Ref_CM;
  UShort_t traces[TRLY_BARCODE_LENGTH]; //All channels
};

#define MAKE_BARCODE_STRING(len) HELPER_BARCODE_STRING(len)
#define HELPER_BARCODE_STRING(len) \
const char * const trolley_barcode_str = "local_clock/l:len_per_ch/s:Sampling_Period/s:Acquisition_Delay/s:DAC_1_Config/s:DAC_2_Config/s:Ref_CM/s:traces["#len"]/s"
MAKE_BARCODE_STRING(TRLY_BARCODE_LENGTH);

struct trolley_monitor_t{
  ULong64_t local_clock_cycle_start;
  UInt_t PMonitorVal;
  UInt_t PMonitorTemp;
  UInt_t RFPower1;
  UInt_t RFPower2;
  UInt_t NMRCheckSum;
  UInt_t ConfigCheckSum;
  UInt_t FrameCheckSum;
  UInt_t NMRFrameSum;
  UInt_t ConfigFrameSum;
  UInt_t FrameSum;
  UInt_t FrameIndex;
  UShort_t StatusBits;
  UShort_t TMonitorIn;
  UShort_t TMonitorExt1;
  UShort_t TMonitorExt2;
  UShort_t TMonitorExt3;
  UShort_t V1Min;
  UShort_t V1Max;
  UShort_t V2Min;
  UShort_t V2Max;
  UShort_t length_per_ch;
  UShort_t Trolley_Command;
  UShort_t TIC_Stop;
  UShort_t TC_Start;
  UShort_t TD_Start;
  UShort_t TC_Stop;
  UShort_t Switch_RF;
  UShort_t PowerEnable;
  UShort_t RF_Enable;
  UShort_t Switch_Comm;
  UShort_t TIC_Start;
  UShort_t Cycle_Length;
  UShort_t Power_Control_1;
  UShort_t Power_Control_2;
  UShort_t trace_VMonitor1[TRLY_MONITOR_LENGTH];
  UShort_t trace_VMonitor2[TRLY_MONITOR_LENGTH];
};

#define MAKE_MONITOR_STRING(len) HELPER_MONITOR_STRING(len)
#define HELPER_MONITOR_STRING(len) \
const char * const trolley_monitor_str = "local_clock_cycle_start/l:PMonitorVal/i:PMonitorTemp/i:RFPower1/i:RFPower2/i:"\
"NMRCheckSum/i:ConfigCheckSum/i:FrameCheckSum/i:NMRFrameSum/i:ConfigFrameSum/i:FrameSum/i:FrameIndex/i:StatusBits/s:"\
"TMonitorIn/s:TMonitorExt1/s:TMonitorExt2/s:TMonitorExt3/s:V1Min/s:V1Max/s:V2Min/s:V2Max/s:len_per_ch/s:"\
"Trolley Command/s:TIC_Stop/s:TC_Start/s:TD_Start/s:TC_Stop/s:Switch_RF/s:PowerEnable/s:RF_Enable/s:"\
"Switch_Comm/s:TIC_Start/s:Cycle_Length/s:Power_Control_1/s:Power_Control_2/s:"\
"trace_VMonitor1["#len"]/s:trace_VMonitor2["#len"]/s"
MAKE_MONITOR_STRING(TRLY_MONITOR_LENGTH);

struct trolley_interface_t{
  ULong64_t gps_clock_cycle_start;
  ULong64_t local_clock_cycle_start;
  ULong64_t local_clock_iv;
  UInt_t rf_power0;
  UInt_t rf_power1;
  UShort_t rf_switch_offset;
  UShort_t comm_switch_offset;
  UShort_t n_iv_samples;
  UShort_t power_protection_trip;
  UShort_t power_status;
  UShort_t ldo_temp_monitor_min;
  UShort_t ldo_temp_monitor_max;
  UShort_t v_15neg_min;
  UShort_t v_15neg_max;
  UShort_t v_15pos_min;
  UShort_t v_15pos_max;
  UShort_t v_5_min;
  UShort_t v_5_max;
  UShort_t v_33_min;
  UShort_t v_33_max;
  UShort_t trace_v_monitor[TRLY_INTERFACE_MONITOR_LENGTH];
  UShort_t trace_i_monitor[TRLY_INTERFACE_MONITOR_LENGTH];
};

#define MAKE_INTERFACE_STRING(len) HELPER_INTERFACE_STRING(len)
#define HELPER_INTERFACE_STRING(len) \
const char * const trolley_interface_str = "gps_clock_cycle_start/l:local_clock_cycle_start/l:local_clock_iv/l:"\
"rf_power0/i:rf_power1/i:rf_switch_offset/s:comm_switch_offset/s:n_iv_samples/s:power_protection_trip/s:power_status/s:"\
"ldo_temp_monitor_min/s:ldo_temp_monitor_max/s:v_15neg_min/s:v_15neg_max/s:v_15pos_min/s:v_15pos_max/s:"\
"v_5_min/s:v_5_max/s:v_33_min/s:v_33_max/s:trace_v_monitor["#len"]/s:trace_i_monitor["#len"]/s"
MAKE_INTERFACE_STRING(TRLY_INTERFACE_MONITOR_LENGTH);

struct trolley_extra_t{
  Double_t GalilTime;
  Int_t Source;
  Int_t GalilPos[2];
  Int_t GalilVel[2];
};

#define MAKE_TRLYEXTRA_STRING() HELPER_TRLYEXTRA_STRING()
#define HELPER_TRLYEXTRA_STRING() \
const char * const trolley_extra_str = "GalilTIME/D:GalilPos[2]/I:GalilVel[2]/I"
MAKE_TRLYEXTRA_STRING();

//Galil Data structs
struct galil_trolley_t{
  ULong64_t TimeStamp;
  Int_t Tensions[2];
  Int_t Temperatures[2];
  Int_t Positions[3];
  Int_t Velocities[3];
  Int_t OutputVs[3];
};

const char * const galil_trolley_str = "TimeStamp/l:Tensions[2]/I:Temperatures[2]:Positions[3]/I:Velocities[3]/I:OutputVs[3]/I";

struct galil_plunging_probe_t{
  ULong64_t TimeStamp;
  Int_t Positions[3];
  Int_t Velocities[3];
  Int_t OutputVs[3];
};

const char * const galil_plunging_probe_str = "TimeStamp/l:Positions[3]/I:Velocities[3]/I:OutputVs[3]/I";

//Absolute probe data struct
struct absolute_nmr_info_t{
  ULong64_t time_stamp;
  UInt_t length;
  Int_t Pos[4]; //Coordinate X,Y,Z,S
  UShort_t flay_run_number;
  UShort_t probe_index;
  //Because the length of the trace varies too much, it is not included in this struct
};

#define MAKE_ABSNMR_STRING() HELPER_ABSNMR_STRING()
#define HELPER_ABSNMR_STRING() \
const char * const absolute_nmr_info_str = "time_stamp/l:length/i:Pos[4]/i:flay_run_number/s:probe_index/s"
MAKE_ABSNMR_STRING();

// Absolute calibration NMR structs
MAKE_NMR_STRUCT(abs_fixed_t, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);
MAKE_NMR_STRING(abs_fixed_str, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);

MAKE_NMR_STRUCT(abs_online_fixed_t, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);
MAKE_NMR_STRING(abs_online_fixed_str, ABS_NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);

//Surface coil struct
struct surface_coil_t{
  Double_t bot_sys_clock[SC_NUM_COILS];
  Double_t top_sys_clock[SC_NUM_COILS];
  Double_t bot_coil_currents[SC_NUM_COILS];
  Double_t top_coil_currents[SC_NUM_COILS];
  Double_t bot_coil_temps[SC_NUM_COILS];
  Double_t top_coil_temps[SC_NUM_COILS];
};

#define MAKE_SC_STRING(name,num_coils) SC_HELPER(name,num_coils)

#define SC_HELPER(name,num_coils)\
const char * const name = "sys_clock["#num_coils"]/D:bot_coil_currents["#num_coils"]/D:top_coil_currents["#num_coils"]/D:bot_coil_temps["#num_coils"]/D:top_coil_temps["#num_coils"]/D"

MAKE_SC_STRING(sc_str,SC_NUM_COILS);

// Yokogawa struct
struct yokogawa_t{
   ULong64_t sys_clock;   // system clock
   ULong64_t gps_clock;   // GPS clock
   Int_t mode;            // device mode (0 = voltage, 1 = current)
   Int_t is_enabled;      // is the output enabled (0 = false, 1 = true)
   Double_t current;      // current setting (in mA)
   Double_t voltage;      // voltage setting (in V)
};

#define MAKE_YOKO_STRING() HELPER_YOKO_STRING()
#define HELPER_YOKO_STRING() \
const char * const yokogawa_str = "sys_clock/l:gps_clock/l:is_enabled/i:current/D"
MAKE_YOKO_STRING();

} // ::g2field

#endif
<|endoftext|>


<commit_before>#include "systems.h"
#include "compiler.h"
#include "mswin.h"
#include "resources.h"
#include "vector.h"
#include "make_system.h"
#include "cramer.h"
#include "graphics.h"
#include "memory.h"
#include <cstdint>

struct triangle_t
{
  float xyz [3] [4]; // Co-ordinates for a single triangle XYZ of the Moebius tiling.
  float abc [8] [4]; // Coefficients A, B, C for the generator T = AX + BY + CZ.
};

// The fundamental triangle of the tiling has angles
// A = pi/p, B = pi/q, C = pi/r and sides a, b, c.

// By the spherical cosine rule,
// cosa = (cosA + cosB * cosC) / (sinB * sinC),
// cosb = (cosB + cosC * cosA) / (sinC * sinA),
// cosc = (cosC + cosA * cosB) / (sinA * sinB).

// We assume p = 2, so cosA = 0 and sinA = 1. Therefore,
// cosa = (cosB * cosC) / (sinB * sinC),
// cosb = cosB / sinC,
// cosc = cosC / sinB.

// A triple (alpha, beta, gamma) identifies a point T relative to the
// spherical triangle XYZ, by the formula
// T = alpha * X + beta * Y + gamma * Z.
// Certain points on the triangle generate uniform polyhedra:

// { 1, 0, 0, },             Point X.
// { 0, 1, 0, },             Point Y.
// { 0, 0, 1, },             Point Z.
// { 0, sinb, sinc, },       Intersection of YZ with the angular bisector of X.
// { sina, 0, sinc, },       Intersection of ZX with the angular bisector of Y.
// { sina, sinb, 0, },       Intersection of YZ with the angular bisector of Z.
// { sinA, sinB, sinC, },    Incentre (intersection of the bisectors).
// { alpha, beta, gamma, },  Snub generator.

//     X1
//    /  \
//   Z0--Y0
//   |\  /|
//   | X0 |
//   |/  \|
//   Y1  Z1

// For the snub generator, the three points (see diagram)
//   TX = alpha * X2 + beta * Y1 + gamma * Z1
//   TY = alpha * X1 + beta * Y2 + gamma * Z1
//   TZ = alpha * X1 + beta * Y1 + gamma * Z2
// are the vertices of an equilateral spherical triangle.
// Assuming p = 2 and q = 3, the ratio beta/alpha satisfies the
// quartic equation
//   c4*x^4 + c2*x^2 + c1*x + c0 = 0
// where
//   c4 = 64 * sinb * sinb
//   c2 = -96 * sinb * sinb
//   c1 = -54 * cosc * sina * sina
//   c0 = 36 * sinb * sinb - 27 * sina * sina
// and gamma/alpha = (sinC / 3) * (4 * (beta / alpha)^2 - 3),

triangle_t triangles [3] ALIGNED16 =
{
  // Tetrahedral, <2, 3, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f, },
      { +0x1.279a74P-1f, +0x0.000000P+0f, +0x1.a20bd8P-1f, 0.0f, },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.3988e2P-1f, +0x1.3988e2P-1f, 0.0f, },
      { +0x1.34bf64P-1f, +0x0.000000P+0f, +0x1.0b621eP-1f, 0.0f, },
      { +0x1.34bf64P-1f, +0x1.0b621eP-1f, +0x0.000000P+0f, 0.0f, },
      { +0x1.c9f25cP-2f, +0x1.8c97f0P-2f, +0x1.8c97f0P-2f, 0.0f, },
      { +0x1.4cb7c0P-2f, +0x1.d2393eP-2f, +0x1.d2393eP-2f, 0.0f, },
    },
  },
  // Octahedral, <2, 4, 3>.
  // Aligned so that two octahedral triangles cover one tetrahedral triangle.
  {
    { { +0x1.6a09e6P-1f, +0x1.000000P-1f, +0x1.000000P-1f, 0.0f, },
      { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f, },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.02ca46P-1f, +0x1.3cf3aeP-1f, 0.0f, },
      { +0x1.1fd4a6P-1f, +0x0.000000P+0f, +0x1.f28990P-2f, 0.0f, },
      { +0x1.43d136P-1f, +0x1.c9f25cP-2f, +0x0.000000P+0f, 0.0f, },
      { +0x1.b9d594P-2f, +0x1.386c8eP-2f, +0x1.7ea3c6P-2f, 0.0f, },
      { +0x1.31816eP-2f, +0x1.8d5502P-2f, +0x1.bdd092P-2f, 0.0f, },
    },
  },
  // Icosahedral, <2, 5, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x1.b38880P-1f, +0x1.0d2ca0P-1f, +0x0.000000P+0f, 0.0f, },
      { +0x1.de4bd6P-1f, +0x0.0000000P+0, +0x1.6d62c6P-2f, 0.0f, },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.b4242aP-2f, +0x1.414c80P-1f, 0.0f, },
      { +0x1.16fc4eP-1f, +0x0.000000P+0f, +0x1.e33798P-2f, 0.0f, },
      { +0x1.4e5014P-1f, +0x1.890220P-2f, +0x0.000000P+0f, 0.0f, },
      { +0x1.b3be36P-2f, +0x1.001f92P-2f, +0x1.795d50P-2f, 0.0f, },
      { +0x1.287f1eP-2f, +0x1.52a52eP-2f, +0x1.b882c6P-2f, 0.0f, },
    },
  }
};

// Turn a PQR triangle into a PRQ triangle.
void reflect (triangle_t & t)
{
  v4f x = load4f (t.xyz [0]);
  v4f y = load4f (t.xyz [1]);
  v4f z = load4f (t.xyz [2]);

  v4f n = normalize (cross (x, y));
  v4f d = dot (n, z) * n;

  store4f (t.xyz [1], z - (d + d));
  store4f (t.xyz [2], y);

  for (unsigned k = 0; k != 8; ++ k) {
    v4f a = load4f (t.abc [k]);
    store4f (t.abc [k], _mm_shuffle_ps (a, a, SHUFFLE (0, 2, 1, 3)));
  }
}

template <unsigned K>
ALWAYS_INLINE inline void copy (const float (* from) [4], float (& to) [K] [4])
{
  for (unsigned k = 0; k != K; ++ k) {
    store4f (to [k], load4f (from [k]));
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
                         float (& xyz) [system_count] [3] [4],
                         float (& xyzinvt) [system_count] [3] [4],
                         unsigned (& primitive_count) [system_count],
                         unsigned (& vao_ids) [system_count])
{
  auto init = [&] (const triangle_t & t, system_select_t select, unsigned q, unsigned r) -> void
  {
    copy (t.xyz, xyz [select]);
    copy (t.abc, abc [select]);
    cramer::inverse_transpose (xyz [select], xyzinvt [select]);
    unsigned p = 2, N = 2 * p * q * r / (q * r + r * p + p * q - p * q * r);
    unsigned indices [60] [6];
    ALIGNED16 float nodes [62] [4];
    make_system (q, r, t.xyz, nodes, indices);
    vao_ids [select] = make_vao (N, nodes, indices);
    primitive_count [select] = N;
  };

  for (unsigned n = 0; n != 3; ++ n) {
    triangle_t & triangle = triangles [n];
    init (triangle, system_select_t (2 * n + 0), 3 + n, 3);
    reflect (triangle);
    init (triangle, system_select_t (2 * n + 1), 3, 3 + n);
  }
}
<commit_msg>systems.cpp: add a caption to the diagram, partly in order to avoid ending the line with a backslash.<commit_after>#include "systems.h"
#include "compiler.h"
#include "mswin.h"
#include "resources.h"
#include "vector.h"
#include "make_system.h"
#include "cramer.h"
#include "graphics.h"
#include "memory.h"
#include <cstdint>

struct triangle_t
{
  float xyz [3] [4]; // Co-ordinates for a single triangle XYZ of the Moebius tiling.
  float abc [8] [4]; // Coefficients A, B, C for the generator T = AX + BY + CZ.
};

// The fundamental triangle of the tiling has angles
// A = pi/p, B = pi/q, C = pi/r and sides a, b, c.

// By the spherical cosine rule,
// cosa = (cosA + cosB * cosC) / (sinB * sinC),
// cosb = (cosB + cosC * cosA) / (sinC * sinA),
// cosc = (cosC + cosA * cosB) / (sinA * sinB).

// We assume p = 2, so cosA = 0 and sinA = 1. Therefore,
// cosa = (cosB * cosC) / (sinB * sinC),
// cosb = cosB / sinC,
// cosc = cosC / sinB.

// A triple (alpha, beta, gamma) identifies a point T relative to the
// spherical triangle XYZ, by the formula
// T = alpha * X + beta * Y + gamma * Z.
// Certain points on the triangle generate uniform polyhedra:

// { 1, 0, 0, },             Point X.
// { 0, 1, 0, },             Point Y.
// { 0, 0, 1, },             Point Z.
// { 0, sinb, sinc, },       Intersection of YZ with the angular bisector of X.
// { sina, 0, sinc, },       Intersection of ZX with the angular bisector of Y.
// { sina, sinb, 0, },       Intersection of YZ with the angular bisector of Z.
// { sinA, sinB, sinC, },    Incentre (intersection of the bisectors).
// { alpha, beta, gamma, },  Snub generator.

//     X1
//    /  \    A portion of the tiling of the sphere, showing
//   Z0--Y0   the triangle X0-Y0-Z0 and the adjacent triangles.
//   |\  /|
//   | X0 |
//   |/  \|
//   Y1  Z1

// For the snub generator, the three points (see diagram)
//   TX = alpha * X2 + beta * Y1 + gamma * Z1
//   TY = alpha * X1 + beta * Y2 + gamma * Z1
//   TZ = alpha * X1 + beta * Y1 + gamma * Z2
// are the vertices of an equilateral spherical triangle.
// Assuming p = 2 and q = 3, the ratio beta/alpha satisfies the
// quartic equation
//   c4*x^4 + c2*x^2 + c1*x + c0 = 0
// where
//   c4 = 64 * sinb * sinb
//   c2 = -96 * sinb * sinb
//   c1 = -54 * cosc * sina * sina
//   c0 = 36 * sinb * sinb - 27 * sina * sina
// and gamma/alpha = (sinC / 3) * (4 * (beta / alpha)^2 - 3),

triangle_t triangles [3] ALIGNED16 =
{
  // Tetrahedral, <2, 3, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f, },
      { +0x1.279a74P-1f, +0x0.000000P+0f, +0x1.a20bd8P-1f, 0.0f, },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.3988e2P-1f, +0x1.3988e2P-1f, 0.0f, },
      { +0x1.34bf64P-1f, +0x0.000000P+0f, +0x1.0b621eP-1f, 0.0f, },
      { +0x1.34bf64P-1f, +0x1.0b621eP-1f, +0x0.000000P+0f, 0.0f, },
      { +0x1.c9f25cP-2f, +0x1.8c97f0P-2f, +0x1.8c97f0P-2f, 0.0f, },
      { +0x1.4cb7c0P-2f, +0x1.d2393eP-2f, +0x1.d2393eP-2f, 0.0f, },
    },
  },
  // Octahedral, <2, 4, 3>.
  // Aligned so that two octahedral triangles cover one tetrahedral triangle.
  {
    { { +0x1.6a09e6P-1f, +0x1.000000P-1f, +0x1.000000P-1f, 0.0f, },
      { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x1.279a74P-1f, +0x1.a20bd8P-1f, +0x0.000000P+0f, 0.0f, },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.02ca46P-1f, +0x1.3cf3aeP-1f, 0.0f, },
      { +0x1.1fd4a6P-1f, +0x0.000000P+0f, +0x1.f28990P-2f, 0.0f, },
      { +0x1.43d136P-1f, +0x1.c9f25cP-2f, +0x0.000000P+0f, 0.0f, },
      { +0x1.b9d594P-2f, +0x1.386c8eP-2f, +0x1.7ea3c6P-2f, 0.0f, },
      { +0x1.31816eP-2f, +0x1.8d5502P-2f, +0x1.bdd092P-2f, 0.0f, },
    },
  },
  // Icosahedral, <2, 5, 3>.
  {
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x1.b38880P-1f, +0x1.0d2ca0P-1f, +0x0.000000P+0f, 0.0f, },
      { +0x1.de4bd6P-1f, +0x0.0000000P+0, +0x1.6d62c6P-2f, 0.0f, },
    },
    { { +0x1.000000P+0f, +0x0.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.000000P+0f, +0x0.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x0.000000P+0f, +0x1.000000P+0f, 0.0f, },
      { +0x0.000000P+0f, +0x1.b4242aP-2f, +0x1.414c80P-1f, 0.0f, },
      { +0x1.16fc4eP-1f, +0x0.000000P+0f, +0x1.e33798P-2f, 0.0f, },
      { +0x1.4e5014P-1f, +0x1.890220P-2f, +0x0.000000P+0f, 0.0f, },
      { +0x1.b3be36P-2f, +0x1.001f92P-2f, +0x1.795d50P-2f, 0.0f, },
      { +0x1.287f1eP-2f, +0x1.52a52eP-2f, +0x1.b882c6P-2f, 0.0f, },
    },
  }
};

// Turn a PQR triangle into a PRQ triangle.
void reflect (triangle_t & t)
{
  v4f x = load4f (t.xyz [0]);
  v4f y = load4f (t.xyz [1]);
  v4f z = load4f (t.xyz [2]);

  v4f n = normalize (cross (x, y));
  v4f d = dot (n, z) * n;

  store4f (t.xyz [1], z - (d + d));
  store4f (t.xyz [2], y);

  for (unsigned k = 0; k != 8; ++ k) {
    v4f a = load4f (t.abc [k]);
    store4f (t.abc [k], _mm_shuffle_ps (a, a, SHUFFLE (0, 2, 1, 3)));
  }
}

template <unsigned K>
ALWAYS_INLINE inline void copy (const float (* from) [4], float (& to) [K] [4])
{
  for (unsigned k = 0; k != K; ++ k) {
    store4f (to [k], load4f (from [k]));
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
                         float (& xyz) [system_count] [3] [4],
                         float (& xyzinvt) [system_count] [3] [4],
                         unsigned (& primitive_count) [system_count],
                         unsigned (& vao_ids) [system_count])
{
  auto init = [&] (const triangle_t & t, system_select_t select, unsigned q, unsigned r) -> void
  {
    copy (t.xyz, xyz [select]);
    copy (t.abc, abc [select]);
    cramer::inverse_transpose (xyz [select], xyzinvt [select]);
    unsigned p = 2, N = 2 * p * q * r / (q * r + r * p + p * q - p * q * r);
    unsigned indices [60] [6];
    ALIGNED16 float nodes [62] [4];
    make_system (q, r, t.xyz, nodes, indices);
    vao_ids [select] = make_vao (N, nodes, indices);
    primitive_count [select] = N;
  };

  for (unsigned n = 0; n != 3; ++ n) {
    triangle_t & triangle = triangles [n];
    init (triangle, system_select_t (2 * n + 0), 3 + n, 3);
    reflect (triangle);
    init (triangle, system_select_t (2 * n + 1), 3, 3 + n);
  }
}
<|endoftext|>


<commit_before>#include "endpoint.h"

#include <stdexcept>
#include <set>
#include <mysql.h>

#include "database_client.h"
#include "row_printer.h"

#define MYSQL_5_6_5 50605

class MySQLRes {
public:
	MySQLRes(MYSQL &mysql, bool buffer);
	~MySQLRes();

	inline MYSQL_RES *res() { return _res; }
	inline int n_tuples() const { return _n_tuples; }
	inline int n_columns() const { return _n_columns; }

private:
	MYSQL_RES *_res;
	int _n_tuples;
	int _n_columns;
};

MySQLRes::MySQLRes(MYSQL &mysql, bool buffer) {
	_res = buffer ? mysql_store_result(&mysql) : mysql_use_result(&mysql);
	_n_tuples = mysql_num_rows(_res);
	_n_columns = mysql_num_fields(_res);
}

MySQLRes::~MySQLRes() {
	if (_res) {
		while (mysql_fetch_row(_res)) ; // must throw away any remaining results or else they'll be returned in the next requested resultset!
		mysql_free_result(_res);
	}
}

class MySQLRow {
public:
	inline MySQLRow(MySQLRes &res, MYSQL_ROW row): _res(res), _row(row) { _lengths = mysql_fetch_lengths(_res.res()); }
	inline const MySQLRes &results() const { return _res; }

	inline         int n_columns() const { return _res.n_columns(); }
	inline        bool   null_at(int column_number) const { return     _row[column_number] == NULL; }
	inline const void *result_at(int column_number) const { return     _row[column_number]; }
	inline         int length_of(int column_number) const { return _lengths[column_number]; }
	inline      string string_at(int column_number) const { return string((char *)result_at(column_number), length_of(column_number)); }

private:
	MySQLRes &_res;
	MYSQL_ROW _row;
	unsigned long *_lengths;
};

class MySQLClient: public DatabaseClient {
public:
	typedef MySQLRow RowType;

	MySQLClient(
		const char *database_host,
		const char *database_port,
		const char *database_name,
		const char *database_username,
		const char *database_password);
	~MySQLClient();

	template <typename RowReceiver>
	void retrieve_rows(const Table &table, const ColumnValues &prev_key, size_t row_count, RowReceiver &row_packer) {
		query(retrieve_rows_sql(table, prev_key, row_count, '`'), row_packer, false /* as above */);
	}

	template <typename RowReceiver>
	void retrieve_rows(const Table &table, const ColumnValues &prev_key, const ColumnValues &last_key, RowReceiver &row_packer) {
		query(retrieve_rows_sql(table, prev_key, last_key, '`'), row_packer, false /* nb. n_tuples won't work, which is ok since we send rows individually */);
	}

	void execute(const string &sql);
	void disable_referential_integrity();
	void enable_referential_integrity();
	string export_snapshot();
	void import_snapshot(const string &snapshot);
	void unhold_snapshot();
	void start_read_transaction();
	void start_write_transaction();
	void commit_transaction();
	void rollback_transaction();
	string escape_value(const string &value);

	inline const char* replace_sql_prefix() { return "REPLACE INTO "; }
	inline char quote_identifiers_with() { return '`'; }

	inline bool need_primary_key_clearer_to_replace() { return false; /* not needed since we support REPLACE */ }

	template <typename UniqueKeyClearerClass>
	inline void add_replace_clearers(vector<UniqueKeyClearerClass> &unique_key_clearers, const Table &table) { /* not needed since we support REPLACE */ }

protected:
	friend class MySQLTableLister;

	void populate_database_schema();

	template <typename RowFunction>
	void query(const string &sql, RowFunction &row_handler, bool buffer) {
		if (mysql_real_query(&mysql, sql.c_str(), sql.length())) {
			backtrace();
			throw runtime_error(mysql_error(&mysql) + string("\n") + sql);
		}

		MySQLRes res(mysql, buffer);

		while (true) {
			MYSQL_ROW mysql_row = mysql_fetch_row(res.res());
			if (!mysql_row) break;
			MySQLRow row(res, mysql_row);
			row_handler(row);
		}

		// check again for errors, as mysql_fetch_row would return NULL for both errors & no more rows
		if (mysql_errno(&mysql)) {
			backtrace();
			throw runtime_error(mysql_error(&mysql) + string("\n") + sql);
		}
	}

private:
	MYSQL mysql;

	// forbid copying
	MySQLClient(const MySQLClient& copy_from) { throw logic_error("copying forbidden"); }
};

MySQLClient::MySQLClient(
	const char *database_host,
	const char *database_port,
	const char *database_name,
	const char *database_username,
	const char *database_password) {

	// mysql_real_connect takes separate params for numeric ports and unix domain sockets
	int port = 0;
	const char *socket = NULL;
	if (database_port && *database_port) {
		if (*database_port >= '0' && *database_port <= '9') {
			port = atoi(database_port);
		} else {
			socket = database_port;
		}
	}

	mysql_init(&mysql);
	mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "ks_mysql");
	mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "binary");
	if (!mysql_real_connect(&mysql, database_host, database_username, database_password, database_name, port, socket, 0)) {
		throw runtime_error(mysql_error(&mysql));
	}

	// increase the timeouts so that the connection doesn't get killed while trying to write large rowsets to the client over slow pipes
	execute("SET SESSION net_read_timeout = 300, net_write_timeout = 600");
}

MySQLClient::~MySQLClient() {
	mysql_close(&mysql);
}

void MySQLClient::execute(const string &sql) {
	if (mysql_real_query(&mysql, sql.c_str(), sql.size())) {
		throw runtime_error(mysql_error(&mysql) + string("\n") + sql);
	}
}

void MySQLClient::start_read_transaction() {
	execute("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
	execute(mysql_get_server_version(&mysql) >= MYSQL_5_6_5 ? "START TRANSACTION READ ONLY WITH CONSISTENT SNAPSHOT" : "START TRANSACTION WITH CONSISTENT SNAPSHOT");
	populate_database_schema();
}

void MySQLClient::start_write_transaction() {
	execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED"); // use read committed instead of the default repeatable read - we don't want to take gap locks
	execute("START TRANSACTION");
	populate_database_schema();
}

void MySQLClient::commit_transaction() {
	execute("COMMIT");
}

void MySQLClient::rollback_transaction() {
	execute("ROLLBACK");
}

string MySQLClient::export_snapshot() {
	// mysql's system catalogs are non-transactional and do not give a consistent snapshot; furthermore,
	// it doesn't support export/import of transactions, so we need to exclude other transactions while
	// we start up our set of read transactions so that they see consistent data.
	execute("FLUSH TABLES"); // wait for current update statements to finish, without blocking other connections
	execute("FLUSH TABLES WITH READ LOCK"); // then block other connections from updating/committing
	start_read_transaction(); // and start our transaction, and signal the other workers to start theirs
	return "locked";
}

void MySQLClient::import_snapshot(const string &snapshot) { // note the argument isn't needed for mysql
	start_read_transaction();
}

void MySQLClient::unhold_snapshot() {
	execute("UNLOCK TABLES");
}

void MySQLClient::disable_referential_integrity() {
	execute("SET foreign_key_checks = 0");
}

void MySQLClient::enable_referential_integrity() {
	execute("SET foreign_key_checks = 1");
}

string MySQLClient::escape_value(const string &value) {
	string result;
	result.resize(value.size()*2 + 1);
	size_t result_length = mysql_real_escape_string(&mysql, (char*)result.data(), value.c_str(), value.size());
	result.resize(result_length);
	return result;
}

struct MySQLColumnLister {
	inline MySQLColumnLister(Table &table): table(table) {}

	inline void operator()(MySQLRow &row) {
		Column column(row.string_at(0));
		table.columns.push_back(column);
	}

	Table &table;
};

struct MySQLKeyLister {
	inline MySQLKeyLister(Table &table): table(table) {}

	inline void operator()(MySQLRow &row) {
		bool unique = (row.string_at(1) == "0");
		string key_name = row.string_at(2);
		string column_name = row.string_at(4);
		size_t column_index = table.index_of_column(column_name);
		// FUTURE: consider representing collation, sub_part, packed, index_type, and perhaps comment/index_comment

		if (key_name == "PRIMARY") {
			// there is of course only one primary key; we get a row for each column it includes
			table.primary_key_columns.push_back(column_index);

		} else {
			// a column in a generic key, which may or may not be unique
			if (table.keys.empty() || table.keys.back().name != key_name) {
				table.keys.push_back(Key(key_name, unique));
			}
			table.keys.back().columns.push_back(column_index);

			if (table.primary_key_columns.empty()) {
				// if we have no primary key, we might need to use another unique key as a surrogate - see MySQLTableLister below -
				// but this key must have no NULLable columns, as they effectively make the index not unique
				string nullable = row.string_at(9);
				if (unique && nullable == "YES") {
					// mark this as unusable
					unique_but_nullable_keys.insert(key_name);
				}
			}
		}
	}

	Table &table;
	set<string> unique_but_nullable_keys;
};

struct MySQLTableLister {
	inline MySQLTableLister(MySQLClient &client): _client(client) {}

	inline void operator()(MySQLRow &row) {
		Table table(row.string_at(0));

		MySQLColumnLister column_lister(table);
		_client.query("SHOW COLUMNS FROM " + table.name, column_lister, false);

		MySQLKeyLister key_lister(table);
		_client.query("SHOW KEYS FROM " + table.name, key_lister, false);

		// if the table has no primary key, we need to find a unique key with no nullable columns to act as a surrogate primary key
		sort(table.keys.begin(), table.keys.end()); // order is arbitrary for keys, but both ends must be consistent, so we sort the keys by name

		for (Keys::const_iterator key = table.keys.begin(); key != table.keys.end() && table.primary_key_columns.empty(); ++key) {
			if (key->unique && !key_lister.unique_but_nullable_keys.count(key->name)) {
				table.primary_key_columns = key->columns;
			}
		}
		if (table.primary_key_columns.empty()) {
			// of course this falls apart if there are no unique keys, so we don't allow that
			throw runtime_error("Couldn't find a primary or non-nullable unique key on table " + table.name);
		}

		_client.database.tables.push_back(table);
	}

private:
	MySQLClient &_client;
};

void MySQLClient::populate_database_schema() {
	MySQLTableLister table_lister(*this);
	query("SELECT table_name FROM information_schema.tables WHERE table_schema = schema() ORDER BY data_length DESC, table_name ASC", table_lister, true /* buffer so we can make further queries during iteration */);
	index_database_tables();
}

int main(int argc, char *argv[]) {
	return endpoint_main<MySQLClient>(argc, argv);
}
<commit_msg>remove n_tuples from MysqlRes, won't be set if using SQL_NO_CACHE<commit_after>#include "endpoint.h"

#include <stdexcept>
#include <set>
#include <mysql.h>

#include "database_client.h"
#include "row_printer.h"

#define MYSQL_5_6_5 50605

class MySQLRes {
public:
	MySQLRes(MYSQL &mysql, bool buffer);
	~MySQLRes();

	inline MYSQL_RES *res() { return _res; }
	inline int n_columns() const { return _n_columns; }

private:
	MYSQL_RES *_res;
	int _n_columns;
};

MySQLRes::MySQLRes(MYSQL &mysql, bool buffer) {
	_res = buffer ? mysql_store_result(&mysql) : mysql_use_result(&mysql);
	_n_columns = mysql_num_fields(_res);
}

MySQLRes::~MySQLRes() {
	if (_res) {
		while (mysql_fetch_row(_res)) ; // must throw away any remaining results or else they'll be returned in the next requested resultset!
		mysql_free_result(_res);
	}
}

class MySQLRow {
public:
	inline MySQLRow(MySQLRes &res, MYSQL_ROW row): _res(res), _row(row) { _lengths = mysql_fetch_lengths(_res.res()); }
	inline const MySQLRes &results() const { return _res; }

	inline         int n_columns() const { return _res.n_columns(); }
	inline        bool   null_at(int column_number) const { return     _row[column_number] == NULL; }
	inline const void *result_at(int column_number) const { return     _row[column_number]; }
	inline         int length_of(int column_number) const { return _lengths[column_number]; }
	inline      string string_at(int column_number) const { return string((char *)result_at(column_number), length_of(column_number)); }

private:
	MySQLRes &_res;
	MYSQL_ROW _row;
	unsigned long *_lengths;
};

class MySQLClient: public DatabaseClient {
public:
	typedef MySQLRow RowType;

	MySQLClient(
		const char *database_host,
		const char *database_port,
		const char *database_name,
		const char *database_username,
		const char *database_password);
	~MySQLClient();

	template <typename RowReceiver>
	void retrieve_rows(const Table &table, const ColumnValues &prev_key, size_t row_count, RowReceiver &row_packer) {
		query(retrieve_rows_sql(table, prev_key, row_count, '`'), row_packer, false /* as above */);
	}

	template <typename RowReceiver>
	void retrieve_rows(const Table &table, const ColumnValues &prev_key, const ColumnValues &last_key, RowReceiver &row_packer) {
		query(retrieve_rows_sql(table, prev_key, last_key, '`'), row_packer, false /* nb. n_tuples won't work, which is ok since we send rows individually */);
	}

	void execute(const string &sql);
	void disable_referential_integrity();
	void enable_referential_integrity();
	string export_snapshot();
	void import_snapshot(const string &snapshot);
	void unhold_snapshot();
	void start_read_transaction();
	void start_write_transaction();
	void commit_transaction();
	void rollback_transaction();
	string escape_value(const string &value);

	inline const char* replace_sql_prefix() { return "REPLACE INTO "; }
	inline char quote_identifiers_with() { return '`'; }

	inline bool need_primary_key_clearer_to_replace() { return false; /* not needed since we support REPLACE */ }

	template <typename UniqueKeyClearerClass>
	inline void add_replace_clearers(vector<UniqueKeyClearerClass> &unique_key_clearers, const Table &table) { /* not needed since we support REPLACE */ }

protected:
	friend class MySQLTableLister;

	void populate_database_schema();

	template <typename RowFunction>
	void query(const string &sql, RowFunction &row_handler, bool buffer) {
		if (mysql_real_query(&mysql, sql.c_str(), sql.length())) {
			backtrace();
			throw runtime_error(mysql_error(&mysql) + string("\n") + sql);
		}

		MySQLRes res(mysql, buffer);

		while (true) {
			MYSQL_ROW mysql_row = mysql_fetch_row(res.res());
			if (!mysql_row) break;
			MySQLRow row(res, mysql_row);
			row_handler(row);
		}

		// check again for errors, as mysql_fetch_row would return NULL for both errors & no more rows
		if (mysql_errno(&mysql)) {
			backtrace();
			throw runtime_error(mysql_error(&mysql) + string("\n") + sql);
		}
	}

private:
	MYSQL mysql;

	// forbid copying
	MySQLClient(const MySQLClient& copy_from) { throw logic_error("copying forbidden"); }
};

MySQLClient::MySQLClient(
	const char *database_host,
	const char *database_port,
	const char *database_name,
	const char *database_username,
	const char *database_password) {

	// mysql_real_connect takes separate params for numeric ports and unix domain sockets
	int port = 0;
	const char *socket = NULL;
	if (database_port && *database_port) {
		if (*database_port >= '0' && *database_port <= '9') {
			port = atoi(database_port);
		} else {
			socket = database_port;
		}
	}

	mysql_init(&mysql);
	mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "ks_mysql");
	mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "binary");
	if (!mysql_real_connect(&mysql, database_host, database_username, database_password, database_name, port, socket, 0)) {
		throw runtime_error(mysql_error(&mysql));
	}

	// increase the timeouts so that the connection doesn't get killed while trying to write large rowsets to the client over slow pipes
	execute("SET SESSION net_read_timeout = 300, net_write_timeout = 600");
}

MySQLClient::~MySQLClient() {
	mysql_close(&mysql);
}

void MySQLClient::execute(const string &sql) {
	if (mysql_real_query(&mysql, sql.c_str(), sql.size())) {
		throw runtime_error(mysql_error(&mysql) + string("\n") + sql);
	}
}

void MySQLClient::start_read_transaction() {
	execute("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
	execute(mysql_get_server_version(&mysql) >= MYSQL_5_6_5 ? "START TRANSACTION READ ONLY WITH CONSISTENT SNAPSHOT" : "START TRANSACTION WITH CONSISTENT SNAPSHOT");
	populate_database_schema();
}

void MySQLClient::start_write_transaction() {
	execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED"); // use read committed instead of the default repeatable read - we don't want to take gap locks
	execute("START TRANSACTION");
	populate_database_schema();
}

void MySQLClient::commit_transaction() {
	execute("COMMIT");
}

void MySQLClient::rollback_transaction() {
	execute("ROLLBACK");
}

string MySQLClient::export_snapshot() {
	// mysql's system catalogs are non-transactional and do not give a consistent snapshot; furthermore,
	// it doesn't support export/import of transactions, so we need to exclude other transactions while
	// we start up our set of read transactions so that they see consistent data.
	execute("FLUSH TABLES"); // wait for current update statements to finish, without blocking other connections
	execute("FLUSH TABLES WITH READ LOCK"); // then block other connections from updating/committing
	start_read_transaction(); // and start our transaction, and signal the other workers to start theirs
	return "locked";
}

void MySQLClient::import_snapshot(const string &snapshot) { // note the argument isn't needed for mysql
	start_read_transaction();
}

void MySQLClient::unhold_snapshot() {
	execute("UNLOCK TABLES");
}

void MySQLClient::disable_referential_integrity() {
	execute("SET foreign_key_checks = 0");
}

void MySQLClient::enable_referential_integrity() {
	execute("SET foreign_key_checks = 1");
}

string MySQLClient::escape_value(const string &value) {
	string result;
	result.resize(value.size()*2 + 1);
	size_t result_length = mysql_real_escape_string(&mysql, (char*)result.data(), value.c_str(), value.size());
	result.resize(result_length);
	return result;
}

struct MySQLColumnLister {
	inline MySQLColumnLister(Table &table): table(table) {}

	inline void operator()(MySQLRow &row) {
		Column column(row.string_at(0));
		table.columns.push_back(column);
	}

	Table &table;
};

struct MySQLKeyLister {
	inline MySQLKeyLister(Table &table): table(table) {}

	inline void operator()(MySQLRow &row) {
		bool unique = (row.string_at(1) == "0");
		string key_name = row.string_at(2);
		string column_name = row.string_at(4);
		size_t column_index = table.index_of_column(column_name);
		// FUTURE: consider representing collation, sub_part, packed, index_type, and perhaps comment/index_comment

		if (key_name == "PRIMARY") {
			// there is of course only one primary key; we get a row for each column it includes
			table.primary_key_columns.push_back(column_index);

		} else {
			// a column in a generic key, which may or may not be unique
			if (table.keys.empty() || table.keys.back().name != key_name) {
				table.keys.push_back(Key(key_name, unique));
			}
			table.keys.back().columns.push_back(column_index);

			if (table.primary_key_columns.empty()) {
				// if we have no primary key, we might need to use another unique key as a surrogate - see MySQLTableLister below -
				// but this key must have no NULLable columns, as they effectively make the index not unique
				string nullable = row.string_at(9);
				if (unique && nullable == "YES") {
					// mark this as unusable
					unique_but_nullable_keys.insert(key_name);
				}
			}
		}
	}

	Table &table;
	set<string> unique_but_nullable_keys;
};

struct MySQLTableLister {
	inline MySQLTableLister(MySQLClient &client): _client(client) {}

	inline void operator()(MySQLRow &row) {
		Table table(row.string_at(0));

		MySQLColumnLister column_lister(table);
		_client.query("SHOW COLUMNS FROM " + table.name, column_lister, false);

		MySQLKeyLister key_lister(table);
		_client.query("SHOW KEYS FROM " + table.name, key_lister, false);

		// if the table has no primary key, we need to find a unique key with no nullable columns to act as a surrogate primary key
		sort(table.keys.begin(), table.keys.end()); // order is arbitrary for keys, but both ends must be consistent, so we sort the keys by name

		for (Keys::const_iterator key = table.keys.begin(); key != table.keys.end() && table.primary_key_columns.empty(); ++key) {
			if (key->unique && !key_lister.unique_but_nullable_keys.count(key->name)) {
				table.primary_key_columns = key->columns;
			}
		}
		if (table.primary_key_columns.empty()) {
			// of course this falls apart if there are no unique keys, so we don't allow that
			throw runtime_error("Couldn't find a primary or non-nullable unique key on table " + table.name);
		}

		_client.database.tables.push_back(table);
	}

private:
	MySQLClient &_client;
};

void MySQLClient::populate_database_schema() {
	MySQLTableLister table_lister(*this);
	query("SELECT table_name FROM information_schema.tables WHERE table_schema = schema() ORDER BY data_length DESC, table_name ASC", table_lister, true /* buffer so we can make further queries during iteration */);
	index_database_tables();
}

int main(int argc, char *argv[]) {
	return endpoint_main<MySQLClient>(argc, argv);
}
<|endoftext|>


<commit_before>#include <log4cxx/logger.h>
#include <KrisLibrary/Logger.h>
#include "Path.h"
#include <math/random.h>
#include <Timer.h>
#include <errors.h>

MilestonePath::MilestonePath()
{}

MilestonePath::~MilestonePath()
{}

void MilestonePath::Concat(const MilestonePath& path)
{
  edges.reserve(edges.size()+path.edges.size());
  for(size_t i=0;i<path.edges.size();i++) {
    edges.push_back(path.edges[i]);
  }
}

bool MilestonePath::InitializeEdgePlans()
{
  bool res=true;
  for(size_t i=0;i<edges.size();i++) {
    if(!edges[i]->IsVisible()) res=false;
  }
  return res;
}

void MilestonePath::CreateEdgesFromMilestones(CSpace* space,const vector<Config>& milestones)
{
  Assert(!milestones.empty());
  edges.resize(milestones.size()-1);
  for(size_t i=0;i+1<milestones.size();i++) {
    edges[i] = space->LocalPlanner(milestones[i],milestones[i+1]);
  }
}

bool MilestonePath::IsFeasible()
{
  if(edges.empty()) return true;
  //first check endpoints
  CSpace* space=Space();
  if(!space->IsFeasible(edges[0]->Start())) return false;
  for(size_t i=0;i<edges.size();i++) {
    if(!space->IsFeasible(edges[i]->End())) return false;
  }
  //then check edges
  for(size_t i=0;i<edges.size();i++)
    if(!edges[i]->IsVisible()) return false;
  return true;
}

int MilestonePath::Eval2(Real t, Config& c) const
{
  if(t <= Zero) { c = edges.front()->Start(); return 0; }
  else if(t >= One) { c = edges.back()->End(); return edges.size()-1; }
  else {
    Real u=t*(Real)edges.size();
    Real u0=Floor(u);
    int index = (int)u0;
    Assert(index >= 0 && index < (int)edges.size());
    edges[index]->Eval(u-u0,c);
    return index;
  }
}

int MilestonePath::Shortcut()
{
  int numShortcuts=0;
  size_t i=0;
  while(i+1 < edges.size()) {
    //try to connect milestone i to i+2
    const Config& x1=GetMilestone(i);
    const Config& x2=GetMilestone(i+2);
    EdgePlanner* e= IsVisible(edges[i]->Space(),x1,x2);
    if(e) {
      edges[i]=e;
      edges.erase(edges.begin()+i+1);
      numShortcuts++;
      //don't advance to next milestone
    }
    else //advance to next milestone
      i++;
  }
  return numShortcuts;
}

int MilestonePath::Reduce(int numIters)
{
  CSpace* space=Space();
  //pick random points on the path, connect them if they're visible
  Config x1,x2;
  int i1,i2;
  int numsplices=0;
  for(int iters=0;iters<numIters;iters++) {
    i1 = rand()%edges.size();
    i2 = rand()%edges.size();
    if(i2 < i1) swap(i1,i2);
    else if(i1 == i2) {
      continue;  //if they're on the same segment, forget it
    }

    Real t1=Rand();
    Real t2=Rand();
    edges[i1]->Eval(t1,x1);
    edges[i2]->Eval(t2,x2);
    const Config& a=edges[i1]->Start();
    const Config& b=edges[i2]->End();
    EdgePlanner* e_x1x2=space->LocalPlanner(x1,x2);
    Timer timer;
    if(e_x1x2->IsVisible()) {
      EdgePlanner* e_ax1=space->LocalPlanner(a,x1);
      EdgePlanner* e_x2b=space->LocalPlanner(x2,b);
      if(e_ax1->IsVisible() && e_x2b->IsVisible()) {
	numsplices++;
	//LOG4CXX_INFO(KrisLibrary::logger(),"Visible subsegment "<<i1<<"->"<<i2<<"\n");
	//replace edges a->a',...,b'->b with a->x1,x1->x2,x2->b
	edges.erase(edges.begin()+i1,edges.begin()+i2+1);

	edges.insert(edges.begin()+i1,e_ax1);
	edges.insert(edges.begin()+i1+1,e_x1x2);
	edges.insert(edges.begin()+i1+2,e_x2b);
      }
      else {
	delete e_ax1;
	delete e_x2b;
      }
    }
    else {
      delete e_x1x2;
    }
  }
  return numsplices;
}

void MilestonePath::Discretize(Real h)
{
  for(size_t i=0;i<edges.size();i++) {
    int n=DiscretizeEdge(i,h);
    i+=n-1;
  }
}

int MilestonePath::DiscretizeEdge(int i,Real h)
{
  EdgePlanner* e=edges[i];
  const Config& a=e->Start();
  const Config& b=e->End();
  CSpace* space=e->Space();
  int numDivs = (int)Ceil(e->Length()/h);
  //don't do anything...
  if(numDivs <= 1) return 1;

  //create a bunch of replacement edges
  Real du=One/numDivs;
  Real u=0;
  Config x1,x2;
  MilestonePath replacement;
  for(int k=0;k<numDivs;k++) {
    if(k==0) x1=a;
    else e->Eval(u,x1);
    if(k+1==numDivs) x2=b;
    else e->Eval(u+du,x2);
    EdgePlanner* e2 = space->PathChecker(x1,x2);
    if(e2->IsVisible())
      replacement.edges.push_back(e2);
    else {
      LOG4CXX_ERROR(KrisLibrary::logger(),"Warning, reparameterized edge "<<i<<" is infeasible"<<"\n");
      replacement.edges.push_back(e2);
    }
    u += du;
  }
  Assert(!replacement.edges.empty());
  Splice(i,i+1,replacement);
  return replacement.edges.size();
}

void MilestonePath::DiscretizeEdge(int i,const vector<Real>& u)
{
  Assert(u.front()==0 && u.back()==1);
  EdgePlanner* e=edges[i];
  CSpace* space=e->Space();
  if(u.size()==2) return;

  Config x1,x2;
  MilestonePath replacement;
  x1 = e->Start();
  for(size_t k=1;k<u.size();k++) {
    e->Eval(u[k],x2);
    EdgePlanner* e2 = space->PathChecker(x1,x2);
    if(e2->IsVisible())
      replacement.edges.push_back(e2);
    else {
      LOG4CXX_ERROR(KrisLibrary::logger(),"Warning, reparameterized edge "<<i<<" is infeasible"<<"\n");
      replacement.edges.push_back(e2);
    }
    x1 = x2;
  }
  Splice(i,i+1,replacement);
}

bool MilestonePath::IsValid()
{
  if(edges.empty()) return false;
  CSpace* space=Space();
  for(size_t i=0;i<edges.size();i++) {
    if(Space(i) != space) return false;
    if(i!=0)
      if(edges[i]->Start() != edges[i-1]->End()) return false;
  }
  return true;
}

Real MilestonePath::Length() const
{
  Real len=0;
  for(size_t i=0;i<edges.size();i++)
    len += edges[i]->Length();
  return len;
}

const Config& MilestonePath::GetMilestone(int i) const
{
  Assert(i>=0 && i<=(int)edges.size());
  if(i==(int)edges.size())
    return edges.back()->End();
  return edges[i]->Start();
}

void MilestonePath::SetMilestone(int i,const Config& x)
{
  if(i == 0) {
    //first milestone
    const Config& b=edges[i]->End();
    edges[i] = Space(i)->LocalPlanner(x,b);
  }
  else if(i==(int)edges.size()) {
    Assert(!edges.empty());
    //last milestone
    const Config& a=edges[i-1]->Start();
    edges[i-1] = Space(i-1)->LocalPlanner(a,x);
  }
  else {
    const Config& a=edges[i-1]->Start();
    const Config& b=edges[i]->End();
    edges[i-1] = Space(i-1)->LocalPlanner(a,x);
    edges[i] = Space(i)->LocalPlanner(x,b);
  }
}

bool MilestonePath::CheckSetMilestone(int i,const Config& x)
{
  if(i == 0) {
    //first milestone
    const Config& b=edges[i]->End();
    EdgePlanner* e2=IsVisible(Space(i),x,b);
    if(!e2) return false;
    edges[i] = e2;
    return true;
  }
  else if(i==(int)edges.size()) {
    Assert(!edges.empty());
    //last milestone
    const Config& a=edges[i-1]->Start();
    EdgePlanner* e1=IsVisible(Space(i-1),a,x);
    if(!e1) return false;
    edges[i-1] = e1;
    return true;
  }
  else {
    const Config& a=edges[i-1]->Start();
    const Config& b=edges[i]->End();
    EdgePlanner* e1=IsVisible(Space(i-1),a,x);
    if(!e1) return false;
    EdgePlanner* e2=IsVisible(Space(i),x,b);
    if(!e2) { delete e1; return false; }

    edges[i-1] = e1;
    edges[i] = e2;
    return true;
  }
}

void MilestonePath::Splice(int start,int goal,const MilestonePath& path)
{
  if(start >= 0) Assert(start <= (int)edges.size());
  if(goal >= 0) Assert(goal <= (int)edges.size());
  if(start < 0) start=0;
  if(goal < 0) goal=(int)edges.size();
  edges.erase(edges.begin()+start,edges.begin()+goal);
  edges.insert(edges.begin()+start,path.edges.begin(),path.edges.end());
}

bool MilestonePath::Load(istream& in,CSpace* space)
{
  Assert(space != NULL);
  vector<Config> configs;
  int n;
  in>>n;
  if(in.bad()) return false;
  Assert(n > 0);
  configs.reserve(n);
  Config temp;
  for(int i=0;i<n;i++) {
    in>>temp;
    configs.push_back(temp);
  }
  CreateEdgesFromMilestones(space,configs);
  return true;
}

bool MilestonePath::Save(ostream& out)
{
  Assert(!edges.empty());
  out<<edges.size()+1<<endl;
  for(size_t i=0;i<edges.size();i++)
    out<<edges[i]->Start()<<endl;
  out<<edges.back()->End()<<endl;
  return true;
}
<commit_msg>Fixed memory leak<commit_after>#include <log4cxx/logger.h>
#include <KrisLibrary/Logger.h>
#include "Path.h"
#include <math/random.h>
#include <Timer.h>
#include <errors.h>

MilestonePath::MilestonePath()
{}

MilestonePath::~MilestonePath()
{}

void MilestonePath::Concat(const MilestonePath& path)
{
  edges.reserve(edges.size()+path.edges.size());
  for(size_t i=0;i<path.edges.size();i++) {
    edges.push_back(path.edges[i]);
  }
}

bool MilestonePath::InitializeEdgePlans()
{
  bool res=true;
  for(size_t i=0;i<edges.size();i++) {
    if(!edges[i]->IsVisible()) res=false;
  }
  return res;
}

void MilestonePath::CreateEdgesFromMilestones(CSpace* space,const vector<Config>& milestones)
{
  Assert(!milestones.empty());
  edges.resize(milestones.size()-1);
  for(size_t i=0;i+1<milestones.size();i++) {
    edges[i] = space->LocalPlanner(milestones[i],milestones[i+1]);
  }
}

bool MilestonePath::IsFeasible()
{
  if(edges.empty()) return true;
  //first check endpoints
  CSpace* space=Space();
  if(!space->IsFeasible(edges[0]->Start())) return false;
  for(size_t i=0;i<edges.size();i++) {
    if(!space->IsFeasible(edges[i]->End())) return false;
  }
  //then check edges
  for(size_t i=0;i<edges.size();i++)
    if(!edges[i]->IsVisible()) return false;
  return true;
}

int MilestonePath::Eval2(Real t, Config& c) const
{
  if(t <= Zero) { c = edges.front()->Start(); return 0; }
  else if(t >= One) { c = edges.back()->End(); return edges.size()-1; }
  else {
    Real u=t*(Real)edges.size();
    Real u0=Floor(u);
    int index = (int)u0;
    Assert(index >= 0 && index < (int)edges.size());
    edges[index]->Eval(u-u0,c);
    return index;
  }
}

int MilestonePath::Shortcut()
{
  int numShortcuts=0;
  size_t i=0;
  while(i+1 < edges.size()) {
    //try to connect milestone i to i+2
    const Config& x1=GetMilestone(i);
    const Config& x2=GetMilestone(i+2);
    EdgePlanner* e= IsVisible(edges[i]->Space(),x1,x2);
    if(e) {
      edges[i]=e;
      edges.erase(edges.begin()+i+1);
      numShortcuts++;
      //don't advance to next milestone
    }
    else //advance to next milestone
      i++;
  }
  return numShortcuts;
}

int MilestonePath::Reduce(int numIters)
{
  CSpace* space=Space();
  //pick random points on the path, connect them if they're visible
  Config x1,x2;
  int i1,i2;
  int numsplices=0;
  for(int iters=0;iters<numIters;iters++) {
    i1 = rand()%edges.size();
    i2 = rand()%edges.size();
    if(i2 < i1) swap(i1,i2);
    else if(i1 == i2) {
      continue;  //if they're on the same segment, forget it
    }

    Real t1=Rand();
    Real t2=Rand();
    edges[i1]->Eval(t1,x1);
    edges[i2]->Eval(t2,x2);
    const Config& a=edges[i1]->Start();
    const Config& b=edges[i2]->End();
    EdgePlanner* e_x1x2=space->LocalPlanner(x1,x2);
    Timer timer;
    if(e_x1x2->IsVisible()) {
      EdgePlanner* e_ax1=space->LocalPlanner(a,x1);
      EdgePlanner* e_x2b=space->LocalPlanner(x2,b);
      if(e_ax1->IsVisible() && e_x2b->IsVisible()) {
	numsplices++;
	//LOG4CXX_INFO(KrisLibrary::logger(),"Visible subsegment "<<i1<<"->"<<i2<<"\n");
	//replace edges a->a',...,b'->b with a->x1,x1->x2,x2->b
	edges.erase(edges.begin()+i1,edges.begin()+i2+1);

	edges.insert(edges.begin()+i1,e_ax1);
	edges.insert(edges.begin()+i1+1,e_x1x2);
	edges.insert(edges.begin()+i1+2,e_x2b);
      }
      else {
	delete e_ax1;
	delete e_x2b;
  delete e_x1x2;
      }
    }
    else {
      delete e_x1x2;
    }
  }
  return numsplices;
}

void MilestonePath::Discretize(Real h)
{
  for(size_t i=0;i<edges.size();i++) {
    int n=DiscretizeEdge(i,h);
    i+=n-1;
  }
}

int MilestonePath::DiscretizeEdge(int i,Real h)
{
  EdgePlanner* e=edges[i];
  const Config& a=e->Start();
  const Config& b=e->End();
  CSpace* space=e->Space();
  int numDivs = (int)Ceil(e->Length()/h);
  //don't do anything...
  if(numDivs <= 1) return 1;

  //create a bunch of replacement edges
  Real du=One/numDivs;
  Real u=0;
  Config x1,x2;
  MilestonePath replacement;
  for(int k=0;k<numDivs;k++) {
    if(k==0) x1=a;
    else e->Eval(u,x1);
    if(k+1==numDivs) x2=b;
    else e->Eval(u+du,x2);
    EdgePlanner* e2 = space->PathChecker(x1,x2);
    if(e2->IsVisible())
      replacement.edges.push_back(e2);
    else {
      LOG4CXX_ERROR(KrisLibrary::logger(),"Warning, reparameterized edge "<<i<<" is infeasible"<<"\n");
      replacement.edges.push_back(e2);
    }
    u += du;
  }
  Assert(!replacement.edges.empty());
  Splice(i,i+1,replacement);
  return replacement.edges.size();
}

void MilestonePath::DiscretizeEdge(int i,const vector<Real>& u)
{
  Assert(u.front()==0 && u.back()==1);
  EdgePlanner* e=edges[i];
  CSpace* space=e->Space();
  if(u.size()==2) return;

  Config x1,x2;
  MilestonePath replacement;
  x1 = e->Start();
  for(size_t k=1;k<u.size();k++) {
    e->Eval(u[k],x2);
    EdgePlanner* e2 = space->PathChecker(x1,x2);
    if(e2->IsVisible())
      replacement.edges.push_back(e2);
    else {
      LOG4CXX_ERROR(KrisLibrary::logger(),"Warning, reparameterized edge "<<i<<" is infeasible"<<"\n");
      replacement.edges.push_back(e2);
    }
    x1 = x2;
  }
  Splice(i,i+1,replacement);
}

bool MilestonePath::IsValid()
{
  if(edges.empty()) return false;
  CSpace* space=Space();
  for(size_t i=0;i<edges.size();i++) {
    if(Space(i) != space) return false;
    if(i!=0)
      if(edges[i]->Start() != edges[i-1]->End()) return false;
  }
  return true;
}

Real MilestonePath::Length() const
{
  Real len=0;
  for(size_t i=0;i<edges.size();i++)
    len += edges[i]->Length();
  return len;
}

const Config& MilestonePath::GetMilestone(int i) const
{
  Assert(i>=0 && i<=(int)edges.size());
  if(i==(int)edges.size())
    return edges.back()->End();
  return edges[i]->Start();
}

void MilestonePath::SetMilestone(int i,const Config& x)
{
  if(i == 0) {
    //first milestone
    const Config& b=edges[i]->End();
    edges[i] = Space(i)->LocalPlanner(x,b);
  }
  else if(i==(int)edges.size()) {
    Assert(!edges.empty());
    //last milestone
    const Config& a=edges[i-1]->Start();
    edges[i-1] = Space(i-1)->LocalPlanner(a,x);
  }
  else {
    const Config& a=edges[i-1]->Start();
    const Config& b=edges[i]->End();
    edges[i-1] = Space(i-1)->LocalPlanner(a,x);
    edges[i] = Space(i)->LocalPlanner(x,b);
  }
}

bool MilestonePath::CheckSetMilestone(int i,const Config& x)
{
  if(i == 0) {
    //first milestone
    const Config& b=edges[i]->End();
    EdgePlanner* e2=IsVisible(Space(i),x,b);
    if(!e2) return false;
    edges[i] = e2;
    return true;
  }
  else if(i==(int)edges.size()) {
    Assert(!edges.empty());
    //last milestone
    const Config& a=edges[i-1]->Start();
    EdgePlanner* e1=IsVisible(Space(i-1),a,x);
    if(!e1) return false;
    edges[i-1] = e1;
    return true;
  }
  else {
    const Config& a=edges[i-1]->Start();
    const Config& b=edges[i]->End();
    EdgePlanner* e1=IsVisible(Space(i-1),a,x);
    if(!e1) return false;
    EdgePlanner* e2=IsVisible(Space(i),x,b);
    if(!e2) { delete e1; return false; }

    edges[i-1] = e1;
    edges[i] = e2;
    return true;
  }
}

void MilestonePath::Splice(int start,int goal,const MilestonePath& path)
{
  if(start >= 0) Assert(start <= (int)edges.size());
  if(goal >= 0) Assert(goal <= (int)edges.size());
  if(start < 0) start=0;
  if(goal < 0) goal=(int)edges.size();
  edges.erase(edges.begin()+start,edges.begin()+goal);
  edges.insert(edges.begin()+start,path.edges.begin(),path.edges.end());
}

bool MilestonePath::Load(istream& in,CSpace* space)
{
  Assert(space != NULL);
  vector<Config> configs;
  int n;
  in>>n;
  if(in.bad()) return false;
  Assert(n > 0);
  configs.reserve(n);
  Config temp;
  for(int i=0;i<n;i++) {
    in>>temp;
    configs.push_back(temp);
  }
  CreateEdgesFromMilestones(space,configs);
  return true;
}

bool MilestonePath::Save(ostream& out)
{
  Assert(!edges.empty());
  out<<edges.size()+1<<endl;
  for(size_t i=0;i<edges.size();i++)
    out<<edges[i]->Start()<<endl;
  out<<edges.back()->End()<<endl;
  return true;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGenericDataSet.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkGenericDataSet.h"

#include <assert.h>

#include "vtkGenericAttributeCollection.h"
#include "vtkMath.h"
#include "vtkCellTypes.h"
#include "vtkGenericCellIterator.h"
#include "vtkGenericAdaptorCell.h"
#include "vtkGenericCellTessellator.h"

vtkCxxRevisionMacro(vtkGenericDataSet, "1.5");
vtkCxxSetObjectMacro(vtkGenericDataSet, Tessellator,vtkGenericCellTessellator);

//----------------------------------------------------------------------------
vtkGenericDataSet::vtkGenericDataSet()
{
  this->Tessellator = 0;
  this->Attributes = vtkGenericAttributeCollection::New();
  vtkMath::UninitializeBounds(this->Bounds);
}

//----------------------------------------------------------------------------
vtkGenericDataSet::~vtkGenericDataSet()
{
  if(this->Tessellator!=0)
    {
    this->Tessellator->Delete();
    }
  this->Attributes->Delete();
}

//----------------------------------------------------------------------------
void vtkGenericDataSet::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Number Of Points: " << this->GetNumberOfPoints() << "\n";
  os << indent << "Number Of Cells: " << this->GetNumberOfCells() << "\n";

  os << indent << "Attributes:\n";
  this->GetAttributes()->PrintSelf(os,indent.GetNextIndent());

  this->ComputeBounds();
  os << indent << "Bounds: \n";
  os << indent << "  Xmin,Xmax: (" <<this->Bounds[0] << ", " << this->Bounds[1] << ")\n";
  os << indent << "  Ymin,Ymax: (" <<this->Bounds[2] << ", " << this->Bounds[3] << ")\n";
  os << indent << "  Zmin,Zmax: (" <<this->Bounds[4] << ", " << this->Bounds[5] << ")\n";

  os << indent << "Tessellator:" << this->Tessellator << endl;
}

//----------------------------------------------------------------------------
// Description:
// Get a list of types of cells in a dataset. The list consists of an array
// of types (not necessarily in any order), with a single entry per type.
// For example a dataset 5 triangles, 3 lines, and 100 hexahedra would
// result a list of three entries, corresponding to the types VTK_TRIANGLE,
// VTK_LINE, and VTK_HEXAHEDRON.
// THIS METHOD IS THREAD SAFE IF FIRST CALLED FROM A SINGLE THREAD AND
// THE DATASET IS NOT MODIFIED
// \pre types_exist: types!=0
void vtkGenericDataSet::GetCellTypes(vtkCellTypes *types)
{
  assert("pre: types_exist" && types!=0);

  unsigned char type;
  vtkGenericCellIterator *it=this->NewCellIterator(-1);
  vtkGenericAdaptorCell *c=it->NewCell();

  types->Reset();
  it->Begin();
  while(!it->IsAtEnd())
    {
    it->GetCell(c);
    type=c->GetType();
    if ( ! types->IsType(type) )
      {
      types->InsertNextType(type);
      }
    it->Next();
    }
  c->Delete();
  it->Delete();
}

//----------------------------------------------------------------------------
// Return a pointer to the geometry bounding box in the form
// (xmin,xmax, ymin,ymax, zmin,zmax).
// The return value is VOLATILE.
// \post result_exists: result!=0
double *vtkGenericDataSet::GetBounds()
{
  this->ComputeBounds();
  return this->Bounds;
}

//----------------------------------------------------------------------------
 // Description:
// Return the geometry bounding box in global coordinates in
// the form (xmin,xmax, ymin,ymax, zmin,zmax) into `bounds'.
void vtkGenericDataSet::GetBounds(double bounds[6])
{
  this->ComputeBounds();
  memcpy(bounds,this->Bounds,sizeof(double)*6);
}

//----------------------------------------------------------------------------
// Description:
// Get the center of the bounding box in global coordinates.
// The return value is VOLATILE.
// - \post result_exists: result!=0
double *vtkGenericDataSet::GetCenter()
{
  this->ComputeBounds();
  for (int i=0; i<3; i++)
    {
    this->Center[i] = (this->Bounds[2*i+1] + this->Bounds[2*i]) * 0.5;
    }
  return this->Center;
}

//----------------------------------------------------------------------------
// Description:
// Get the center of the bounding box in global coordinates.
void vtkGenericDataSet::GetCenter(double center[3])
{
  this->ComputeBounds();
  for (int i=0; i<3; i++)
    {
    center[i] = (this->Bounds[2*i+1] + this->Bounds[2*i]) * 0.5;
    }
}

//----------------------------------------------------------------------------
// Description:
// Length of the diagonal of the bounding box.
double vtkGenericDataSet::GetLength()
{
  double result, l=0.0;
  int i;

  this->ComputeBounds();
  for (i=0; i<3; i++)
    {
    result = this->Bounds[2*i+1] - this->Bounds[2*i];
    l += result * result;
    }
  result = sqrt(l);
  assert("post: positive_result" && result>=0);
  return result;
}

//----------------------------------------------------------------------------
unsigned long int vtkGenericDataSet::GetMTime()
{
  unsigned long result;
  unsigned long mtime;

  result = vtkDataObject::GetMTime();

  mtime = this->Attributes->GetMTime();
  result = ( mtime > result ? mtime : result );

  return result;
}

//----------------------------------------------------------------------------
// Description:
// Actual size of the data in kilobytes; only valid after the pipeline has
// updated. It is guaranteed to be greater than or equal to the memory
// required to represent the data.
unsigned long vtkGenericDataSet::GetActualMemorySize()
{
  unsigned long result=this->vtkDataObject::GetActualMemorySize();
  result += this->Attributes->GetActualMemorySize();
  return result;
}

//----------------------------------------------------------------------------
// Description:
// Return the type of data object.
int vtkGenericDataSet::GetDataObjectType()
{
  return VTK_GENERIC_DATA_SET;
}
<commit_msg>BUG:Fixed GetMTime with Tessellator time<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGenericDataSet.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkGenericDataSet.h"

#include <assert.h>

#include "vtkGenericAttributeCollection.h"
#include "vtkMath.h"
#include "vtkCellTypes.h"
#include "vtkGenericCellIterator.h"
#include "vtkGenericAdaptorCell.h"
#include "vtkGenericCellTessellator.h"

vtkCxxRevisionMacro(vtkGenericDataSet, "1.6");
vtkCxxSetObjectMacro(vtkGenericDataSet, Tessellator,vtkGenericCellTessellator);

//----------------------------------------------------------------------------
vtkGenericDataSet::vtkGenericDataSet()
{
  this->Tessellator = 0;
  this->Attributes = vtkGenericAttributeCollection::New();
  vtkMath::UninitializeBounds(this->Bounds);
}

//----------------------------------------------------------------------------
vtkGenericDataSet::~vtkGenericDataSet()
{
  if(this->Tessellator!=0)
    {
    this->Tessellator->Delete();
    }
  this->Attributes->Delete();
}

//----------------------------------------------------------------------------
void vtkGenericDataSet::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Number Of Points: " << this->GetNumberOfPoints() << "\n";
  os << indent << "Number Of Cells: " << this->GetNumberOfCells() << "\n";

  os << indent << "Attributes:\n";
  this->GetAttributes()->PrintSelf(os,indent.GetNextIndent());

  this->ComputeBounds();
  os << indent << "Bounds: \n";
  os << indent << "  Xmin,Xmax: (" <<this->Bounds[0] << ", " << this->Bounds[1] << ")\n";
  os << indent << "  Ymin,Ymax: (" <<this->Bounds[2] << ", " << this->Bounds[3] << ")\n";
  os << indent << "  Zmin,Zmax: (" <<this->Bounds[4] << ", " << this->Bounds[5] << ")\n";

  os << indent << "Tessellator:" << this->Tessellator << endl;
}

//----------------------------------------------------------------------------
// Description:
// Get a list of types of cells in a dataset. The list consists of an array
// of types (not necessarily in any order), with a single entry per type.
// For example a dataset 5 triangles, 3 lines, and 100 hexahedra would
// result a list of three entries, corresponding to the types VTK_TRIANGLE,
// VTK_LINE, and VTK_HEXAHEDRON.
// THIS METHOD IS THREAD SAFE IF FIRST CALLED FROM A SINGLE THREAD AND
// THE DATASET IS NOT MODIFIED
// \pre types_exist: types!=0
void vtkGenericDataSet::GetCellTypes(vtkCellTypes *types)
{
  assert("pre: types_exist" && types!=0);

  unsigned char type;
  vtkGenericCellIterator *it=this->NewCellIterator(-1);
  vtkGenericAdaptorCell *c=it->NewCell();

  types->Reset();
  it->Begin();
  while(!it->IsAtEnd())
    {
    it->GetCell(c);
    type=c->GetType();
    if ( ! types->IsType(type) )
      {
      types->InsertNextType(type);
      }
    it->Next();
    }
  c->Delete();
  it->Delete();
}

//----------------------------------------------------------------------------
// Return a pointer to the geometry bounding box in the form
// (xmin,xmax, ymin,ymax, zmin,zmax).
// The return value is VOLATILE.
// \post result_exists: result!=0
double *vtkGenericDataSet::GetBounds()
{
  this->ComputeBounds();
  return this->Bounds;
}

//----------------------------------------------------------------------------
 // Description:
// Return the geometry bounding box in global coordinates in
// the form (xmin,xmax, ymin,ymax, zmin,zmax) into `bounds'.
void vtkGenericDataSet::GetBounds(double bounds[6])
{
  this->ComputeBounds();
  memcpy(bounds,this->Bounds,sizeof(double)*6);
}

//----------------------------------------------------------------------------
// Description:
// Get the center of the bounding box in global coordinates.
// The return value is VOLATILE.
// - \post result_exists: result!=0
double *vtkGenericDataSet::GetCenter()
{
  this->ComputeBounds();
  for (int i=0; i<3; i++)
    {
    this->Center[i] = (this->Bounds[2*i+1] + this->Bounds[2*i]) * 0.5;
    }
  return this->Center;
}

//----------------------------------------------------------------------------
// Description:
// Get the center of the bounding box in global coordinates.
void vtkGenericDataSet::GetCenter(double center[3])
{
  this->ComputeBounds();
  for (int i=0; i<3; i++)
    {
    center[i] = (this->Bounds[2*i+1] + this->Bounds[2*i]) * 0.5;
    }
}

//----------------------------------------------------------------------------
// Description:
// Length of the diagonal of the bounding box.
double vtkGenericDataSet::GetLength()
{
  double result, l=0.0;
  int i;

  this->ComputeBounds();
  for (i=0; i<3; i++)
    {
    result = this->Bounds[2*i+1] - this->Bounds[2*i];
    l += result * result;
    }
  result = sqrt(l);
  assert("post: positive_result" && result>=0);
  return result;
}

//----------------------------------------------------------------------------
unsigned long int vtkGenericDataSet::GetMTime()
{
  unsigned long result;
  unsigned long mtime;

  result = vtkDataObject::GetMTime();

  mtime = this->Attributes->GetMTime();
  result = ( mtime > result ? mtime : result );

  if(this->Tessellator!=0)
    {
     mtime = this->Tessellator->GetMTime();
     result = ( mtime > result ? mtime : result );
    }

  return result;
}

//----------------------------------------------------------------------------
// Description:
// Actual size of the data in kilobytes; only valid after the pipeline has
// updated. It is guaranteed to be greater than or equal to the memory
// required to represent the data.
unsigned long vtkGenericDataSet::GetActualMemorySize()
{
  unsigned long result=this->vtkDataObject::GetActualMemorySize();
  result += this->Attributes->GetActualMemorySize();
  return result;
}

//----------------------------------------------------------------------------
// Description:
// Return the type of data object.
int vtkGenericDataSet::GetDataObjectType()
{
  return VTK_GENERIC_DATA_SET;
}
<|endoftext|>


<commit_before>#include "TrackingWorker.hpp"

#include <boost/chrono/duration.hpp>
#include <ros/console.h>
#include <opencv2/core/core.hpp>
#include <map>

#include "../matlab/profiling.hpp"

TrackingWorker::TrackingWorker(IPositionReceiver *receiver) : tracker(true), errorGraph(200, "Difference"), positions(50)
{
	assert(receiver != 0);

	this->receiver = receiver;
	stop = false;
	rrCounter = 0;
	maxCamNo = 0;
	bufferSize = 0;
	minUpdateCount = 2;

	std::map<int, cv::Scalar> colors;
	colors[0] = cv::Scalar(0, 255, 0);
	colors[1] = cv::Scalar(0, 255, 255);
	colors[2] = cv::Scalar(255, 0, 255);
	errorGraph.setColors(colors);

	thread = new boost::thread(boost::bind(&TrackingWorker::run, this));
}

TrackingWorker::~TrackingWorker()
{
	stop = true;
	thread->join();
}

void TrackingWorker::run()
{
	ROS_INFO("Started tracking thread");

	bool receivedFirstPosition = false;

	while (!stop) {
		CameraData data = dequeue();

		if (data.valid) {
			// ROS_DEBUG("Got valid data");
			receivedFirstPosition = true;

			long int startTime = getNanoTime();
			Vector position = tracker.updatePosition(data.cameraVector, data.camNo, data.quadcopterId);
			errorGraph.nextPoint(tracker.getDistance(), data.camNo);
			double duration = getNanoTime() - startTime;
			duration /= 1e6;

			std::vector<Vector> positions;
			std::vector<int> ids;
			std::vector<int> updates;
			positions.push_back(position);
			ids.push_back(data.quadcopterId);
			updates.push_back(1);

			if (position.isValid()) {
				receiver->updatePositions(positions, ids, updates);
			} else {
				// ROS_DEBUG("Not enough information to get position of quadcopter %d", data.quadcopterId);
			}

			// ROS_DEBUG("Updating position of quadcopter %d took %.3f ms", data.quadcopterId, duration);
		} else if (receivedFirstPosition) {
			ROS_WARN("Position update buffer is empty!");
		}
	}

	ROS_INFO("Stopped tracking thread");
}

void TrackingWorker::updatePosition(Vector cameraVector, int camNo, int quadcopterId)
{
	CameraData data;
	data.cameraVector = cameraVector;
	data.camNo = camNo;
	data.quadcopterId = quadcopterId;
	data.valid = true;

	updatePosition(data);
}

void TrackingWorker::updatePosition(CameraData data)
{
	// ROS_DEBUG("updatePosition: called");

	enqueue(data);

	// ROS_DEBUG("updatePosition: Inserted CameraData for camera %d and quadcopter %d", data.camNo, data.quadcopterId);
}

void TrackingWorker::enqueue(CameraData data)
{
	// ROS_DEBUG("enqueue: Inserting CameraData");

	{
		boost::mutex::scoped_lock lock(positionsMutex);
		// ROS_DEBUG("enqueue: Got positions lock");

		maxCamNo = maxCamNo > data.camNo ? maxCamNo : data.camNo;
		positions[data.camNo].push(data);

		bufferSize++;

		if (bufferSize > 25) {
			ROS_WARN("Position update buffer is running full (%ld entries). Seems like the position updating can't keep up! Dropping 15 entries.", positions.size());

			int deleted = 0;
			int index = 0;

			while (deleted < 15) {
				if (positions[index].size() > 0) {
					positions[index].pop();
					deleted++;
					bufferSize--;
				}

				index = (index + 1) % maxCamNo;
			}
		}
	}

	// ROS_DEBUG("enqueue: Released positions lock");
	// ROS_DEBUG("enqueue: Notifying about new CameraData");

	positionsEmpty.notify_one();

	// ROS_DEBUG("enqueue: Finished insertion process");
}

CameraData TrackingWorker::dequeue()
{
	// ROS_DEBUG("dequeue: Getting positions lock");

	{
		boost::mutex::scoped_lock lock(positionsMutex);

		// ROS_DEBUG("dequeue: Got positions lock");

		if (!dataAvailable()) {
			positionsEmpty.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(100));
		}

		if (dataAvailable()) {
			do {
				rrCounter++;
				rrCounter %= maxCamNo;
			} while (positions[rrCounter].size() == 0);

			CameraData data = positions[rrCounter].front();
			positions[rrCounter].pop();
			bufferSize--;

			// ROS_DEBUG("dequeue: Released positions lock");
			return data;
		} else {
			CameraData data;
			data.valid = false;

			// ROS_DEBUG("dequeue: Released positions lock");
			return data;
		}
	}
}

bool TrackingWorker::dataAvailable()
{
	for (int i = 0; i < maxCamNo; i++) {
		if (positions[i].size() > 0) {
			return true;
		}
	}

	return false;
}

bool TrackingWorker::haveEnoughData(int count)
{
	int data = 0;

	for (int i = 0; i < maxCamNo; i++) {
		if (positions[i].size() > 0) {
			data++;

			if (data >= count) {
				return true;
			}
		}
	}

	return false;
}

bool TrackingWorker::calibrate(ChessboardData *chessboard, int camNo)
{
	return tracker.calibrate(chessboard, camNo);
}

Vector TrackingWorker::getCameraPosition(int camNo)
{
	return tracker.getPosition(camNo);
}

cv::Mat TrackingWorker::getIntrinsicsMatrix(int camNo)
{
	return tracker.getIntrinsicsMatrix(camNo);
}

cv::Mat TrackingWorker::getDistortionCoefficients(int camNo)
{
	return tracker.getDistortionCoefficients(camNo);
}
<commit_msg>Changed buffer removal<commit_after>#include "TrackingWorker.hpp"

#include <boost/chrono/duration.hpp>
#include <ros/console.h>
#include <opencv2/core/core.hpp>
#include <map>

#include "../matlab/profiling.hpp"

TrackingWorker::TrackingWorker(IPositionReceiver *receiver) : tracker(true), errorGraph(200, "Difference"), positions(50)
{
	assert(receiver != 0);

	this->receiver = receiver;
	stop = false;
	rrCounter = 0;
	maxCamNo = 0;
	bufferSize = 0;
	minUpdateCount = 2;

	std::map<int, cv::Scalar> colors;
	colors[0] = cv::Scalar(0, 255, 0);
	colors[1] = cv::Scalar(0, 255, 255);
	colors[2] = cv::Scalar(255, 0, 255);
	errorGraph.setColors(colors);

	thread = new boost::thread(boost::bind(&TrackingWorker::run, this));
}

TrackingWorker::~TrackingWorker()
{
	stop = true;
	thread->join();
}

void TrackingWorker::run()
{
	ROS_INFO("Started tracking thread");

	bool receivedFirstPosition = false;

	while (!stop) {
		CameraData data = dequeue();

		if (data.valid) {
			// ROS_DEBUG("Got valid data");
			receivedFirstPosition = true;

			long int startTime = getNanoTime();
			Vector position = tracker.updatePosition(data.cameraVector, data.camNo, data.quadcopterId);
			errorGraph.nextPoint(tracker.getDistance(), data.camNo);
			double duration = getNanoTime() - startTime;
			duration /= 1e6;

			std::vector<Vector> positions;
			std::vector<int> ids;
			std::vector<int> updates;
			positions.push_back(position);
			ids.push_back(data.quadcopterId);
			updates.push_back(1);

			if (position.isValid()) {
				receiver->updatePositions(positions, ids, updates);
			} else {
				// ROS_DEBUG("Not enough information to get position of quadcopter %d", data.quadcopterId);
			}

			// ROS_DEBUG("Updating position of quadcopter %d took %.3f ms", data.quadcopterId, duration);
		} else if (receivedFirstPosition) {
			ROS_WARN("Position update buffer is empty!");
		}
	}

	ROS_INFO("Stopped tracking thread");
}

void TrackingWorker::updatePosition(Vector cameraVector, int camNo, int quadcopterId)
{
	CameraData data;
	data.cameraVector = cameraVector;
	data.camNo = camNo;
	data.quadcopterId = quadcopterId;
	data.valid = true;

	updatePosition(data);
}

void TrackingWorker::updatePosition(CameraData data)
{
	// ROS_DEBUG("updatePosition: called");

	enqueue(data);

	// ROS_DEBUG("updatePosition: Inserted CameraData for camera %d and quadcopter %d", data.camNo, data.quadcopterId);
}

void TrackingWorker::enqueue(CameraData data)
{
	// ROS_DEBUG("enqueue: Inserting CameraData");

	{
		boost::mutex::scoped_lock lock(positionsMutex);
		// ROS_DEBUG("enqueue: Got positions lock");

		maxCamNo = maxCamNo > data.camNo ? maxCamNo : data.camNo;
		positions[data.camNo].push(data);

		bufferSize++;

		if (bufferSize > 25) {
			ROS_WARN("Position update buffer is running full (%ld entries). Seems like the position updating can't keep up! Dropping 15 entries.", positions.size());

			int deleted = 0;
			int index = rrCounter;

			while (deleted < 15) {
				if (positions[index].size() > 0) {
					positions[index].pop();
					deleted++;
					bufferSize--;
				}

				index = (index + 1) % maxCamNo;
			}
		}
	}

	// ROS_DEBUG("enqueue: Released positions lock");
	// ROS_DEBUG("enqueue: Notifying about new CameraData");

	positionsEmpty.notify_one();

	// ROS_DEBUG("enqueue: Finished insertion process");
}

CameraData TrackingWorker::dequeue()
{
	// ROS_DEBUG("dequeue: Getting positions lock");

	{
		boost::mutex::scoped_lock lock(positionsMutex);

		// ROS_DEBUG("dequeue: Got positions lock");

		if (!dataAvailable()) {
			positionsEmpty.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(100));
		}

		if (dataAvailable()) {
			do {
				rrCounter++;
				rrCounter %= maxCamNo;
			} while (positions[rrCounter].size() == 0);

			CameraData data = positions[rrCounter].front();
			positions[rrCounter].pop();
			bufferSize--;

			// ROS_DEBUG("dequeue: Released positions lock");
			return data;
		} else {
			CameraData data;
			data.valid = false;

			// ROS_DEBUG("dequeue: Released positions lock");
			return data;
		}
	}
}

bool TrackingWorker::dataAvailable()
{
	for (int i = 0; i < maxCamNo; i++) {
		if (positions[i].size() > 0) {
			return true;
		}
	}

	return false;
}

bool TrackingWorker::haveEnoughData(int count)
{
	int data = 0;

	for (int i = 0; i < maxCamNo; i++) {
		if (positions[i].size() > 0) {
			data++;

			if (data >= count) {
				return true;
			}
		}
	}

	return false;
}

bool TrackingWorker::calibrate(ChessboardData *chessboard, int camNo)
{
	return tracker.calibrate(chessboard, camNo);
}

Vector TrackingWorker::getCameraPosition(int camNo)
{
	return tracker.getPosition(camNo);
}

cv::Mat TrackingWorker::getIntrinsicsMatrix(int camNo)
{
	return tracker.getIntrinsicsMatrix(camNo);
}

cv::Mat TrackingWorker::getDistortionCoefficients(int camNo)
{
	return tracker.getDistortionCoefficients(camNo);
}
<|endoftext|>