#ifndef __INCLUDE_HIS_LOCATION_HPP #define __INCLUDE_HIS_LOCATION_HPP #include #include #include "point.h" #include "log.h" #include "db_api/CDBConnPool.h" //速度 //区域 地图变换 //运动方向 //路径变换 struct location_card { location_card(uint32_t id,uint64_t type) :m_cardid(id) ,m_type(type) { init(); } uint32_t m_cardid;//卡id uint16_t m_type;//卡类型 double m_arg;//运动方向角度值 int m_areaid;//区域 int m_mapid;//地图 uint64_t m_timestamp;//入库后的时间 point m_p;//入库后的点 struct mini_data { mini_data(const point &p,uint64_t t) :p(p) ,time(t) {} point p; uint64_t time; }; std::queue m_d; void init() { m_areaid=-1; m_mapid=-1; m_timestamp=0; m_p.set(0,0); init_att(); } void init_att() { m_arg=0x12345678; std::queue tmp; m_d.swap(tmp); } void set_invalid() { m_arg=0x12345678; } bool is_valid() { return m_arg!=0x12345678; } double make_arg(const point &pt,const point &p) { log_info("his_location arg[%d],(%.2f,%.2f)--->(%.2f,%.2f)---->(%.2f,%.2f)",m_cardid,m_p.x,m_p.y,p.x,p.y,pt.x,pt.y); return std::arg(std::complex(pt.x,pt.y)-std::complex(p.x,p.y)); } void set(const point &pt,uint64_t time) { m_timestamp=time; m_p.set(pt); } bool line_changed(const point &pt) { if(!is_valid()) return false; point p=m_d.back().p; if(p==pt)p=m_p; double arg = make_arg(pt,p); log_info("his_location:line_changed:%d,%.2f,m_arg:%.2f",m_cardid,arg,m_arg); return arg != m_arg; } bool is_speed_changed(const point& pt,uint64_t time) { bool flag = false; double v=0.0; if(m_d.size()>=4) { mini_data d1 = m_d.front(); double dist = d1.p.dist(pt); double t = time-d1.time; v = dist/t*1000; m_d.pop(); } m_d.emplace(pt,time); if(v==0.0) return flag; double dist = m_p.dist(pt); double t = time - m_timestamp; double avge_speed= dist/t*1000; log_info("his_location cardid:%d:v:%.2f,avge_v:%.2f,(%.2f--%.2f)",m_cardid,v,avge_speed,0.8*avge_speed,1.2*avge_speed); if(v<(1-0.2)*avge_speed && v>(1+0.2)*avge_speed) flag=true; return flag; } bool time_out(uint64_t time) { if(time-m_timestamp>=60*1000) return true; return false; } bool is_area_changed(int new_areaid) { bool flag =false; if(m_areaid != new_areaid) { m_areaid = new_areaid; flag=true; } return flag; } bool is_map_changed(int new_mapid) { bool flag =false; if(m_mapid != new_mapid) { m_mapid = new_mapid; flag=true; } return flag; } void push(uint64_t timestamp,const point & p,int32_t areaid,int32_t mapid) { if(m_p.empty() || m_timestamp==0||m_areaid<=0||m_mapid<=0) { set(p,timestamp); m_areaid=areaid;m_mapid=mapid; m_d.emplace(p,timestamp); return; } if(!is_valid()) { if(p==m_p) { init_att();set(p,timestamp); m_d.emplace(p,timestamp); return ; } m_arg=make_arg(p,m_p); log_info("his_location:%d arg:%f",m_cardid,m_arg); insert(); } bool flag=false; bool iflag=false; flag=handle_message(p,timestamp); if(time_out(timestamp)) if(!flag)iflag=true; if(is_speed_changed(p,timestamp)) if(!flag)iflag=true; if(is_area_changed(areaid)) if(!flag)iflag=true; if(is_map_changed(mapid)) if(!flag)iflag=true; if(iflag) { update(p,timestamp); set_invalid(); set(p,timestamp); } } virtual std::string getTabName()=0; void insert() { std::string tabName=getTabName(); char nsql[512]={0}; const char * sql = "replace into %s (card_id,begin_time,map_id,area_id,begin_pt,direction)values(%03d%010d,'%s',%d,%d,'%.2f,%.2f',%f);"; snprintf(nsql,512,sql,tabName.c_str(),m_type,m_cardid,tool_time::to_str_ex(m_timestamp).c_str(),m_mapid,m_areaid,m_p.x,m_p.y,m_arg); log_info("his_location[%d]:%s",m_cardid,nsql); sDBConnPool.PushAsync(nsql); } void update(const point &p,uint64_t timestamp) { std::string tabName=getTabName(); char nsql[512]={0}; const char * sql = "update %s set last_time='%s',speed=%.2f where card_id=%03d%010d and begin_time='%s';"; double dist = m_p.dist(p); double t = timestamp - m_timestamp; double avge_speed= dist/t*1000; snprintf(nsql,512,sql,tabName.c_str(),tool_time::to_str_ex(timestamp).c_str(),avge_speed,m_type,m_cardid,tool_time::to_str_ex(m_timestamp).c_str()); log_info("his_location[%d]:%s",m_cardid,nsql); sDBConnPool.PushAsync(nsql); } virtual bool handle_message(const point &p,uint64_t timestamp)=0; }; struct location_staff:location_card { location_staff(uint32_t id,uint16_t type) :location_card(id,type) {} virtual std::string getTabName(){return std::string{"his_location_staff_"};} //人员如果运行方向发生变化的话,需要求的拐点。如果有拐点,入拐点。时间大与120s则不做处理。没有拐点,则不求 virtual bool handle_message(const point &p,uint64_t timestamp) { bool flag = false; if(line_changed(p)) { log_info("his_location:line_changed %d",m_cardid); flag=true; if(timestamp-m_timestamp>120*1000) { update(m_d.back().p,m_d.back().time); set(p,timestamp); } else { std::vector rc=card_path::inst().find_path(m_p,p); if(rc.empty()) { update(m_d.back().p,m_d.back().time); set(m_d.back().p,m_d.back().time); } else { if(rc.size()==1) { log_info("his_location:line_changed %d circle point(%.2f,%.2f)",m_cardid,rc[0].x,rc[0].y); update(rc[0],m_d.back().time); set(rc[0],m_d.back().time); } else if(rc.size()==2) { update(rc[0],m_d.back().time); set(rc[0],m_d.back().time); // m_arg=make_arg(rc[1],m_p); insert(); // update(rc[1],timestamp); set(rc[1],timestamp); } else//更多的拐点 { update(rc[0],m_d.back().time); set(rc[1],timestamp); } } } init_att(); } return flag; } }; struct location_vehicle:location_card { location_vehicle(uint32_t id,uint16_t type) :location_card(id,type) {} virtual std::string getTabName(){return std::string{"his_location_vehicle_"};} //车辆是有推送拐点的,所以不需要求拐点。如果运行方向发生变化的话,直接更新数据库即可,使用上一个点的时间。同时生成这一次的历史。 virtual bool handle_message(const point &p,uint64_t timestamp) { bool flag =false; if(line_changed(p)) { log_info("his_location:line_changed %d ",m_cardid); flag=true; update(m_d.back().p,m_d.back().time); set(m_d.back().p,m_d.back().time);init_att(); } return flag; } }; #endif