#pragma DISPATCH_USER_CLASS_H #include #include #include "../error_code/error_code.h" #include "database_controller.h" class User_class { const int MAX_SQL_COMMAND_SIZE = 512U; // 最大sql命令长度 const int DAYS_MIN_TIMES = 4; // 判断用户类型的最小认定次数 const int MAX_SAVE_DAYS = 10*24*60*60; // 保留数据库表单时限 const int WORKER_IN_TIME[4] = {6, 7, 9, 10}; // 通勤入库时间函数变量 const int WORKER_OUT_TIME[4] = {16, 17, 19, 20}; // 通勤出库时间函数变量 const int WORKER_PARK_TIME[2] = {3, 4}; // 通勤停车时长函数变量 const int RESIDENT_IN_TIME[4] = {17, 18, 23, 24}; // 居民入库时间函数变量 const int RESIDENT_OUT_TIME[4] = {5, 6, 8, 9}; // 居民出库时间函数变量 const int RESIDENT_PARK_TIME[2] = {4, 5}; // 居民停车时长函数变量 enum USER_CLASS { USER_CLASS_UNKNOW = 0, // 临时用户 USER_CLASS_WORKER, // 通勤用户 USER_CLASS_RESIDENT, // 居民用户 USER_CLASS_STUDY, USER_CLASS_MON_CARD, // 月卡用户 USER_CLASS_NO_STUDY, }; private: /* data */ public: User_class(); ~User_class(); public: static void test(); bool is_vip(const std::string& car_number); Error_manager add_vip(std::string& car_number, time_t& start_time, time_t& end_time); Error_manager delete_vip(std::string& car_number); Error_manager update_vip(std::string& car_number, time_t start_time, time_t end_time); Error_manager update_table(); Error_manager update_table(int save_time); int type(const std::string& car_number); Error_manager type(const std::string& car_number, int& user_type); Error_manager creat_table(const time_t& in_time, const time_t& out_time, const std::string& car_number); private: int time_t_2_int(const time_t& time); Error_manager statistics_table(); Error_manager get_user_type(const std::string& car_number, int& user_type); double fuzzy_model_I(double a, double b, double x); double fuzzy_model_II(double a, double b, double c, double d, double x); private: std::string m_car_number; }; User_class::User_class() {} User_class::~User_class() {} bool User_class::is_vip(const std::string& car_number) { boost::shared_ptr result; std::string sql_command = "select * from vip where car_number = '" + car_number + "'"; Error_manager ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result); if(result->next()) { time_t t = time(NULL); if (result->getInt("end_time") > time_t_2_int(t)) return true; } return false; } Error_manager User_class::add_vip(std::string& car_number, time_t& start_time, time_t& end_time) { if (!is_vip(car_number)) { char sql_command[MAX_SQL_COMMAND_SIZE] = ""; sprintf(sql_command, "insert into vip (start_time, end_time, car_number) values (%d, %d, '%s')\n", time_t_2_int(start_time), time_t_2_int(end_time), car_number.c_str()); Error_manager ec = Database_controller::get_instance_pointer()->sql_insert(sql_command); } else { return update_vip(car_number, start_time, end_time); } return SUCCESS; } Error_manager User_class::delete_vip(std::string& car_number) { std::string sql_command = "delete from vip where car_number = '" + car_number + "'"; Error_manager ec = Database_controller::get_instance_pointer()->sql_delete(sql_command); return SUCCESS; } Error_manager User_class::update_vip(std::string& car_number, time_t start_time, time_t end_time) { char sql_command[MAX_SQL_COMMAND_SIZE] = ""; sprintf(sql_command, "update vip set start_time = %d, end_time = %d where car_number = '%s'", time_t_2_int(start_time), time_t_2_int(end_time), car_number.c_str()); Error_manager ec = Database_controller::get_instance_pointer()->sql_update(sql_command); return SUCCESS; } int User_class::time_t_2_int(const time_t& time) { tm* tt = localtime(&time); return (tt->tm_year + 1900)*10000 + (tt->tm_mon + 1)*100 + tt->tm_mday; } // 对存储的近期用户数据进行综合统计 Error_manager User_class::statistics_table() { // 删除旧的统计结果 boost::shared_ptr result; std::string sql_command = "delete from user_class where record_time = 99999999 "; // 特殊id,用作记录统计数据; Error_manager ec = Database_controller::get_instance_pointer()->sql_delete(sql_command); std::cout << "---Debug--- delete statistics ec = " << ec << std::endl; // 获取全部车牌号 sql_command = "select distinct car_number from user_class"; ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result); std::cout << "---Debug--- ec = " << ec << std::endl; // 对每个车牌重新判断用户类型,并添加到数据库 while (result->next()) { int user_type = USER_CLASS_UNKNOW; get_user_type(result->getString("car_number"), user_type); sql_command = "insert into user_class (record_time, user_type, car_number) values (99999999, " + std::to_string(user_type) + ", '" + result->getString("car_number") + "')"; Database_controller::get_instance_pointer()->sql_insert(sql_command); } // 从数据库获取vip车辆信息,判断是否过期 time_t t = time(NULL); sql_command = "select * from vip where end_time > " + std::to_string(time_t_2_int(t)); ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result); std::cout << "---Debug--- ec = " << ec << std::endl; while (result->next()) { int user_type = USER_CLASS_UNKNOW; sql_command = "insert into user_class (record_time, user_type, car_number) values (99999999, " + std::to_string(USER_CLASS_MON_CARD) + ", '" + result->getString("car_number") + "')"; ec = Database_controller::get_instance_pointer()->sql_insert(sql_command); } return ec; } // 第一类点对点模糊模型 a、b、按照从小到大顺序输入 double User_class::fuzzy_model_I(double a, double b, double x) { if (x > a && x <= b) return 1.00 * ((x - a)/(b - a)); else if (x > b) return 1; else return 0; } // 第二类点对点模糊模型 a、b、c、d、按照从小到大顺序输入 double User_class::fuzzy_model_II(double a, double b, double c, double d, double x) { if (x > a && x <= b) return 1.00 *((x - a)/(b - a)); else if (x > b && x <= c) return 1; else if (x > c && x <= d) return 1.00 * ((d - x)/(d - c)); else return 0; } int User_class::type(const std::string& car_number) { int user_type = 0; type(car_number, user_type); return user_type; } Error_manager User_class::type(const std::string& car_number, int& user_type) { boost::shared_ptr result; std::string sql_command = "select * from user_class where record_time = 99999999 and car_number = '" + car_number + "'"; Error_manager ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result); if (result->next()) { user_type = result->getInt("user_type"); } return ec; } // 从数据库获取用户历史停留信息,并跟据信息判断用户类型; Error_manager User_class::get_user_type(const std::string& car_number, int& user_type) { int worker = 0, resident = 0; boost::shared_ptr result; std::string sql_command = "select * from user_class where user_type > 0 and user_type < 3 and car_number = '" + car_number + "'"; Error_manager ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result); while (result->next()) { if (USER_CLASS_WORKER == result->getInt("user_type")) { worker++; } else { resident++; } } if (worker >= DAYS_MIN_TIMES && worker >= resident) { user_type = USER_CLASS_WORKER; } else if (resident >= DAYS_MIN_TIMES) { user_type = USER_CLASS_RESIDENT; } else { user_type = USER_CLASS_UNKNOW; } return ec; } // 跟据今日时间信息,删除默认设置天数以前的表单数据,更新数据库。 Error_manager User_class::update_table() { return update_table(MAX_SAVE_DAYS); } // 跟据今日时间信息,删除设置天数以前的表单数据,更新数据库。todo:数据库操作判断 Error_manager User_class::update_table(int save_time) { printf("---Debug--- Begain update table.\n"); time_t t_now = time(NULL) - save_time; std::string sql_command = "delete from user_class where record_time < " + std::to_string(time_t_2_int(t_now)); Error_manager ec = Database_controller::get_instance_pointer()->sql_delete(sql_command); std::cout << "---Debug--- delete old ec = " << ec << std::endl; statistics_table(); printf("---Debug--- update table over.\n"); return ec; } // 通过传入的车辆入库、出库时间,计算隶属度,判断用户类型,然后存入到数据库; Error_manager User_class::creat_table(const time_t& in_time, const time_t& out_time, const std::string& car_number) { if(is_vip(car_number)) { return SUCCESS; } // 计算 tm out = *localtime(&out_time); int user_type = USER_CLASS_UNKNOW; double parking_time = (out_time - in_time)/3600.00; double f_in = localtime(&in_time)->tm_hour + localtime(&in_time)->tm_min/60.00; double f_out = localtime(&out_time)->tm_hour + localtime(&out_time)->tm_min/60.00; // 根据入库时间计算隶属度 double s_worker_in, s_worker_out, s_worker_park, s_resident_in, s_resident_out, s_resident_park; double s_worker, s_resident; s_worker_in = fuzzy_model_II(WORKER_IN_TIME[0], WORKER_IN_TIME[1], WORKER_IN_TIME[2], WORKER_IN_TIME[3], f_in); s_worker_out = fuzzy_model_II(WORKER_OUT_TIME[0], WORKER_OUT_TIME[1], WORKER_OUT_TIME[2], WORKER_OUT_TIME[3], f_out); s_worker_park = fuzzy_model_I(WORKER_PARK_TIME[0], WORKER_PARK_TIME[1], parking_time); s_resident_in = fuzzy_model_II(RESIDENT_IN_TIME[0], RESIDENT_IN_TIME[1], RESIDENT_IN_TIME[2], RESIDENT_IN_TIME[3], f_in); s_resident_out = fuzzy_model_II(RESIDENT_OUT_TIME[0], RESIDENT_OUT_TIME[1], RESIDENT_OUT_TIME[2], RESIDENT_OUT_TIME[3], f_out); s_resident_park = fuzzy_model_I(RESIDENT_PARK_TIME[0], RESIDENT_PARK_TIME[1], parking_time); s_worker = s_worker_in + s_worker_out + s_worker_park; s_resident = s_resident_in + s_resident_out + s_resident_park; // 根据隶属度判断用户类型 if (s_worker >= s_resident && s_worker > 1.5) { user_type = USER_CLASS_WORKER; } else if (s_resident >= s_worker && s_resident > 1.5) { user_type = USER_CLASS_RESIDENT; } // 存储车牌、用户类型、日期、到sql char sql_command[MAX_SQL_COMMAND_SIZE] = ""; sprintf(sql_command, "insert into user_class (car_number, record_time, user_type) values ('%s', %d, %d)", car_number.c_str(), time_t_2_int(out_time), user_type); Error_manager ec = Database_controller::get_instance_pointer()->sql_insert(sql_command); return SUCCESS; } void User_class::test() { User_class user_class; user_class.update_table(); int times = 0; while (true && ++times) { printf("-----> No.%d start <-----\n", times); // 随机车牌、入场时间、停车时间 time_t a = time(NULL); tm *tt = localtime(&a); tt->tm_sec = rand() % 61; tt->tm_min = rand() % 61; tt->tm_hour = rand() % 25; tt->tm_mday -= rand()%11 ; // 随机日期,最近十天 time_t in = mktime(tt); time_t out = in + rand()%(24*60*60 + 1); // 最长停留一天 // std::string car_number = "鄂A" + std::to_string(rand()%90000 + 10000); // 车牌 std::string car_number = "鄂A900" + std::to_string(rand()%90 + 10); // 车牌 // std::string car_number = "鄂A98829"; // 添加记录到表格 user_class.creat_table(in, out, car_number); // 获取该车牌类型 int user_type = user_class.type(car_number); std::cout << "---Debug--- " << car_number << " check user_type " << user_type << std::endl; time_t end = in + 30*24*60*60; if (user_type < USER_CLASS_STUDY && user_type > USER_CLASS_UNKNOW) { user_class.add_vip(car_number, in, end); } else if (user_type == USER_CLASS_MON_CARD) { user_class.update_vip(car_number, in, end); } printf("-----> No.%d end <-----\n", times); sleep(1); } }