#include #include #include #include #include #include #include "mine_business.h" #include "log.h" #include "point.h" #include "db/db_api/CDBSingletonDefine.h" #include "db/db_tool.h" #include "common_tool.h" #include "ant.h" #include "sys_setting.h" #include "card_path.h" #include "card.h" #include "area.h" #include "event.h" #include #include #include #include #include #include "wsClientMgr.h" struct card_sensor { card_sensor(int32_t wid,const point &p,const std::string &cid) :card_id(cid) ,sid(0) ,id(wid) ,bigger(-1),count(0),sum(0),ct(-1),stime(0),flag(false),is_alarm(false) { base_point=p; } std::string card_id; int32_t sid; int32_t id; std::vector sensorId_list; point base_point; std::array ant; int8_t bigger; uint32_t count,sum; uint16_t ct; uint64_t stime; bool flag,is_alarm; std::list his_data; std::array dist; void clear() { count=sum=0;stime=0;flag=false; } bool timeout() { time_t t=time(NULL); return flag && t-stime>10*60; } bool check_location_reversal(std::string & str) { time_t t=time(NULL); time_t tval= t-stime; bool f=false; if (tval !=0 && sum*1.0/tval > 0.8 && count*1.0/sum <0.2) f=true; char buf[1024]={0}; sprintf(buf,"[reverse_alarm_checking]%s,count:%d,sum:%d,val:%ld,s:%.2f,v:%.2f,alarm:%d", card_id.c_str(),count,sum,tval,(sum*1.0/tval),(count*1.0/sum),f); str=buf; return f; } void make_reverse_condition(int16_t antid,uint16_t ct,double d) { dist[antid]=d; if(this->ct == ct){ sum++; int b=-1; if (dist[0]>dist[1]) b=0 ;else b =1; if(b==bigger) count++; //合格的点 } this->ct = ct; } void set(const point &p0,const point &p1,int id) { int8_t b=0; ant[0].set(p0);ant[1].set(p1); double d0=base_point.dist(p0);double d1=base_point.dist(p1); if(d0>d1)b=1;else b=0; if (bigger!=-1 && b!=bigger){ count=sum=0;stime=time(0); } bigger=b;sid=id; } bool push(double d){ bool f=true; his_data.push_back(d); if (his_data.size()==3){ double da=0; for (const auto &d:his_data){ if(da>d || d-da<0.004){f=false;break;} da=d; } his_data.pop_front(); } else f=false; return f; } point &operator[](int i){return ant[i];} const point &operator[](int i)const {return ant[i];} void set_true(){flag=true;stime=time(NULL);} bool warning(){return flag;} bool empty(){return his_data.empty();} double back(){return his_data.back();} void clear_sensor(){clear();} int reader_id(){return sid;} void push_back(int32_t sensor_id){sensorId_list.push_back(sensor_id);} }; struct card_sensor_mgr { void push(int32_t wid,int32_t sid,const point &p,const std::string & cardid) { std::shared_ptr cs=nullptr; auto it=m_mgr.find(wid); if(it!=m_mgr.end()) cs=it->second; else { cs=std::make_shared(wid,p,cardid); m_mgr.insert({wid,cs}); } cs->push_back(sid); } void for_each(); void make_condition(int32_t antid,uint32_t ct,uint64_t tof,uint32_t sid); std::map> m_mgr; }; struct staffer_num_business { void record_staffer_num(); void fetch_add(bool bDisplay) { if(bDisplay) m_staff_num++; m_staff_num_real++; } staffer_num_business() { reset(); m_record_staffer_timeval = 0; } uint32_t get_staff_num() const { return m_staff_num.load();} private: void reset() { m_staff_num=0; m_staff_num_real=0; } // 井下考勤并且要显示的人数 std::atomic m_staff_num{0}; // 井下总人数 std::atomic m_staff_num_real{0}; // 通知web最后时间 std::time_t m_record_staffer_timeval; }; struct reverse_alarm_business { void load_sensor(); void load_working_sensor(); void run_sensor(); void get_status(); void make_condition(uint64_t type,uint32_t id,int32_t antid,uint32_t ct,uint64_t tof,uint32_t sid); private: std::map> m_sensor_mgr; std::map m_working_sensor; }; struct rear_end_collision_prevented_business { rear_end_collision_prevented_business() { _time=0;m_v.clear(); } void clear(){m_v.clear();} void put(const std::shared_ptr&c) { m_v.push_back(c); } bool rear_end_arg_algo(uint64_t u1,uint64_t u2); void handle_message(); double get_absolute_distance(uint64_t c1,uint64_t c2); struct car_data { car_data() :_t(0),_arg(0x12345678) {} void push(uint64_t cid,const point &p,uint64_t t) { last_p=_p;_p=p; if (last_p.empty() || _p.empty()) return; if (_p.dist(last_p)<0.5) return; if ( t-_t<5*1000) { _arg = std::arg(std::complex(_p.x,_p.y)-std::complex(last_p.x,last_p.y)); line_v l(last_p,_p);_line=l; std::string card_id = tool_other::get_string_cardid(cid); log_info("[vehicle_alarm_arg ] %s,arg:%f (%.2f,%.2f)--(%.2f,%.2f)",card_id.c_str(),_arg,last_p.x,last_p.y,p.x,p.y); } _t=t; } point last_p,_p; line_v _line; uint64_t _t; double _arg; }; struct vInfo { vInfo() { is_alarm=false; real_end_start_time=0; backfired_start_time=0; } void push(const std::string & c1, const std::string &c2) { m_cid[0]=c1; m_cid[1]=c2; std::sort(m_cid.begin(),m_cid.end()); } std::string getKey() const { return m_cid[0]+"&"+m_cid[1]; } bool is_alarm; std::array m_cid; time_t real_end_start_time ; time_t backfired_start_time; }; void make_arg(uint64_t cid, const point &p,uint64_t t) { m_map[cid].push(cid,p,t); } private: bool invalid_card(const std::shared_ptr &c); time_t _time; std::vector> m_v; std::map m_map; std::map m_CloserVehicle; }; mine_business::mine_business() { m_staffer_num_ptr.reset(new staffer_num_business); m_reverse_alarm_ptr.reset(new reverse_alarm_business); m_rear_ended_ptr.reset(new rear_end_collision_prevented_business); } mine_business* mine_business::inst() { static mine_business mb; return &mb; } void mine_business::run_business() { record_staffer_num(); handle_reverse_alarm(); handle_rear_end(); } void mine_business::fetch_add(bool bDisplay) { m_staffer_num_ptr->fetch_add(bDisplay); } void mine_business::record_staffer_num() { m_staffer_num_ptr->record_staffer_num(); } /* * @brief 加载传感器数据 * @param * @return * @note * @warning * @bug * */ void mine_business::load() { //m_reverse_alarm_ptr->load_sensor(); //m_reverse_alarm_ptr->load_working_sensor(); } void mine_business::handle_reverse_alarm() { m_reverse_alarm_ptr->run_sensor(); } void mine_business::make_reverse_condition(uint64_t type,uint32_t id,int32_t antid,uint32_t ct,uint64_t tof,uint32_t sid) { m_reverse_alarm_ptr->make_condition(type,id,antid,ct,tof,sid); } ///rear ended collision... void mine_business::put(const std::shared_ptr &c) { m_rear_ended_ptr->put(c); } void mine_business::make_arg(uint64_t cid,const point &p,uint64_t t) { m_rear_ended_ptr->make_arg(cid,p,t); } void mine_business::handle_rear_end() { m_rear_ended_ptr->handle_message(); } void mine_business::clear_vehicle() { m_rear_ended_ptr->clear(); } uint32_t mine_business::get_mine_display_staff_num() { return m_staffer_num_ptr->get_staff_num(); } ///////staffer_num_business /********************************** //每两分钟把人员数量入库。 //不往前端推送的人员,不算在数量范围内 *********************************/ void staffer_num_business::record_staffer_num() { static uint32_t min_num=0,max_num=0,min_num_real=0,max_num_real=0; std::time_t t = time(NULL); char ti[64] = { 0 }; strftime(ti,sizeof(ti),"%Y/%m/%d %H:%M:%S",localtime(&t)); std::string sti(ti); int minute = atoi(sti.substr(sti.find_first_of(':')+1,2).c_str()); uint32_t a=m_staff_num.load(); uint32_t ar=m_staff_num_real.load(); if(m_record_staffer_timeval==0) { min_num=max_num=a; min_num_real=max_num_real=ar; m_record_staffer_timeval = t; } if(t-m_record_staffer_timeval>=120 && minute%2 == 0) { std::stringstream ss; ss<< "INSERT INTO his_staff_number(max_num,min_num,ave_num,max_num_real,min_num_real,ave_num_real) VALUES(" <a)min_num = a; if (max_numar)min_num_real = ar; if (max_num_real tm=nullptr; auto iter = m_sensor_mgr.find(cid); if(iter != m_sensor_mgr.end()) tm=iter->second; else { tm = std::make_shared(); m_sensor_mgr.insert({cid,tm}); } point p(bx,by); tm->push(workfaceid,sensor_id,p,card_id); } } /************************************ //获取传感器数据,从数据库中 //每三分钟获取一次,判断其是否上升趋势。 //如果上升趋势,则标识正在掘进中。开始判断反向 ************************************/ void reverse_alarm_business::run_sensor() { static time_t time_interval=0,time_working_interval=0; time_t t = time(NULL); if(t-time_working_interval>1*70) { time_working_interval=t; get_status(); } if (t-time_interval>3*60) { time_interval =t; for(const auto &x:m_sensor_mgr) x.second->for_each(); } } void reverse_alarm_business::get_status() { rapidjson::StringBuffer sb; rapidjson::Writer writer( sb ); rapidjson::Document doc; rapidjson::Document::AllocatorType& Allocator = doc.GetAllocator(); rapidjson::Value LArray( rapidjson::kArrayType ); rapidjson::Value root( rapidjson::kObjectType ); for(const auto &x:m_working_sensor) { char strsql[512]={0}; snprintf(strsql,512, "SELECT data_value FROM his_sensor_data WHERE write_time > DATE_SUB(NOW(),INTERVAL 3 MINUTE) and write_time < now() and sensor_id = %d ORDER BY write_time DESC LIMIT 1;",x.second); std::string Error; YADB::CDBResultSet DBRes; sDBConnPool.Query(strsql,DBRes,Error); int nCount = DBRes.GetRecordCount( Error ); if (nCount < 1) { //log_warn("load_sensor_data..failed[%s]", strsql); logn_warn(2, "load_sensor_data...failed sql=%s", strsql); continue; } if( DBRes.GetNextRecod(Error) ) { rapidjson::Value Array( rapidjson::kArrayType ); rapidjson::Value _DetailItem; rapidjson::Value tmp_object( rapidjson::kObjectType ); int num = 0; DBRes.GetField( "data_value",num, Error ); log_info("working_sensor:%s,%d--%d",x.first.c_str(),x.second,num); num?num=0:num=1; tmp_object.SetString(x.first.c_str() , Allocator ); Array.PushBack( tmp_object, Allocator ); tmp_object.SetInt(num ); Array.PushBack( tmp_object, Allocator ); _DetailItem=Array; LArray.PushBack(_DetailItem, Allocator); } } rapidjson::Value value( rapidjson::kStringType ); value.SetString("vehicle_state", Allocator ); root.AddMember( "cmd", value, Allocator ); if(LArray.Capacity() == 0){ return; } root.AddMember("data",LArray,Allocator); value.SetString("1.0.0.4", Allocator ); root.AddMember( "version", value, Allocator ); root.Accept(writer); std::string vs=sb.GetString(); log_info("vehicle_state:%s",vs.c_str()); swsClientMgr.send( JSON_CMD_VALUE_PUSH,vs); } void card_sensor_mgr::for_each() { for(const auto & cst:m_mgr) { auto cs = cst.second; if(cs->sensorId_list.empty()) continue; char strsql[512]={0}; snprintf(strsql,512, "SELECT data_value FROM his_sensor_data WHERE WHERE write_time > DATE_SUB(NOW(),INTERVAL 10 MINUTE) and sensor_id = %d ORDER BY write_time DESC LIMIT 3;",cs->sensorId_list[0]); std::string Error; YADB::CDBResultSet DBRes; sDBConnPool.Query(strsql,DBRes,Error); int nCount = DBRes.GetRecordCount( Error ); if (nCount < 1) { //log_warn("load_sensor_data..failed[%s]", strsql); logn_warn(2, "load_sensor_data...failed[%s]", strsql); continue; } double prenum=-1; double nrow=0;double sum=0;bool f=false; while ( DBRes.GetNextRecod(Error) ) { double num = 0; DBRes.GetField( "data_value",num, Error ); if (point::eq(num,0,1e-10))continue; //0异常数据抛掉 if(point::eq(prenum,-1,1e-10)){ //如果没有参考数据,则判断,如果有历史数据,用历史,没有则用第一个数据。 if(cs->empty()) prenum=num; else prenum=cs->back(); } if (prenum-num>0.1){ //异常数据 如果之前存在正常数据则继续,如果没有则本次不作参考。0.1暂定 if(cs->empty()){ f=true;break; } else continue; } nrow++;sum+=num; } if (!f && nrow!=0){ double result=sum/nrow; log_info("reverse_alarm_push %s,%.3f",cs->card_id.c_str(),result); if(cs->push(result)){//满足三个并且呈现上升趋势 log_info("reverse_alarm_up %s",cs->card_id.c_str()); if (!cs->warning()) cs->set_true();//置true,主进程开始抓取数据。 } } if (cs->timeout()){//时间满足,判断是否告警 auto reader_it = sit_list::instance()->get(cs->reader_id()); if (!reader_it){ cs->clear_sensor(); continue; } std::string msg; if(cs->check_location_reversal(msg) )//满足告警条件,查看是否已经存在告警,没有产生告警 { log_info("reverse_alarm_create:%s",cs->card_id.c_str()); //产生告警。 //deal_readers_event(ET_READER_LOCATION_REVERSAL,true,reader_it->second); if(!cs->is_alarm) event_tool::instance()->handle_event(OT_DEVICE_READER,ET_READER_LOCATION_REVERSAL,cs->reader_id(),cs->count,cs->sum,cs->is_alarm=true); } else //不满足告警条件,查看是否已经存在告警,存在则取消告警。 { log_info("reverse_alarm_delete:%s",cs->card_id.c_str()); if(cs->is_alarm) event_tool::instance()->handle_event(OT_DEVICE_READER,ET_READER_LOCATION_REVERSAL,cs->reader_id(),cs->count,cs->sum,cs->is_alarm=false); //补 //deal_readers_event(ET_READER_LOCATION_REVERSAL,false,reader_it->second); } log_info("%s",msg.c_str()); cs->clear_sensor();//清除数据,重新判断 } } } /***************************************** //当判断为反向后,则开始手机数据。 //在规定的时间内,记录反向的数量以及双天线数量。 //正常的数量n 总数量s 时长m(秒) //n/s<0.2 && s/m>0.8则标识天线反向 ****************************************/ void reverse_alarm_business::make_condition(uint64_t type,uint32_t id,int32_t antid,uint32_t ct,uint64_t tof,uint32_t sid) { uint64_t cid = tool_other::type_id_to_u64(type,id); auto it = m_sensor_mgr.find(cid); if(it != m_sensor_mgr.end()) it->second->make_condition(antid,ct,tof,sid); } void card_sensor_mgr::make_condition(int32_t antid,uint32_t ct,uint64_t tof,uint32_t sid) { for(const auto x:m_mgr) { auto pdc =x.second; if (pdc->warning()){ auto sit = sit_list::instance()->get(sid); point p0=(*sit)[0];point p1=(*sit)[1]; if (!((*pdc)[0]==p0 && (*pdc)[1]==p1)){ pdc->set(p0,p1,sid); log_info("[reverse_alarm_start]%s,bigger:%d",pdc->card_id.c_str(),pdc->bigger); } log_info("[reverse_alarm_working]%s,ct:%d,antid:%d,dist:%.2f",pdc->card_id.c_str(),ct,antid,tof); pdc->make_reverse_condition(antid,ct,tof); } } } bool rear_end_collision_prevented_business::invalid_card(const std::shared_ptr &c) { bool f=false; uint64_t _now=time(0)*1000; uint64_t ti=c->time_(); uint64_t t=_now>ti?_now-ti:ti-_now; if(t<45*1000 && !c->empty()) f=true; return f; } void rear_end_collision_prevented_business::handle_message() { time_t now = time(0); if(now-_time>3) _time=now; else return; auto it=m_v.cbegin(); for (;it!=m_v.cend();it++) { auto c=*it; if(!invalid_card(c))continue; double map_scale = c->get_area_tool()->m_scale; for (auto prv_it=std::next(it);prv_it!=m_v.cend();++prv_it) { auto c2=*prv_it; if(!invalid_card(c2))continue; double dis = (*c).dist(*c2)*map_scale; log_info("vehicle_alarm stpe3 : cid1:%d,cid2:%d (%.2f,%.2f),(%.2f,%.2f) %.2f,%f",c->m_id,c2->m_id,c->x,c->y,c2->x,c2->y,dis,map_scale); if(dis>CYaSetting::m_sys_setting.rear_end_d) continue; //判断反向行驶,平行行驶,背离行驶的车辆 uint64_t u1=tool_other::type_id_to_u64(c->m_type,c->m_id);uint64_t u2=tool_other::type_id_to_u64(c2->m_type,c2->m_id); if (!rear_end_arg_algo(u1,u2)) continue; // std::string card1=tool_other::type_id_to_str(c->m_type,c->m_id);std::string card2=tool_other::type_id_to_str(c2->m_type,c2->m_id); vInfo v; v.push(card1,card2); std::string cardid=v.getKey(); if(m_CloserVehicle.find(cardid) == m_CloserVehicle.end()) { m_CloserVehicle.insert(std::make_pair(cardid,v)); log_info("vehicle_alarm_insert %s",cardid.c_str()); } } } auto it_cv=m_CloserVehicle.begin(); for (;it_cv != m_CloserVehicle.end();) { vInfo & vinfo = it_cv->second; std::string vvid = it_cv->first; uint64_t u1=tool_other::card_id_to_u64(vinfo.m_cid[0]); uint64_t u2=tool_other::card_id_to_u64(vinfo.m_cid[1]); uint64_t t=now*1000; uint64_t ct=m_map[u1]._t ;uint64_t rt = t>ct?t-ct:ct-t; uint64_t ct_=m_map[u2]._t; uint64_t rt_ = t>ct_?t-ct_:ct_-t; std::hash hsh; uint32_t id = hsh(vvid); if (rt>45*1000 || rt_>45*1000 ) { log_info("vehicle_alarm_time_ %s,%u",vvid.c_str(),id); if (vinfo.is_alarm){ event_tool::instance()->handle_event(OT_CARD,ET_VEHICLE_REAR_END,id,0,0,false,DT_COMMON,vvid); } it_cv = m_CloserVehicle.erase(it_cv); continue; } auto c=card_list::instance()->get(u1); if(!c) continue; double map_scale = c->get_area_tool()->m_scale; double dis = get_absolute_distance(u1,u2)*map_scale; log_info("vehicle_alarm_distance %s %f",vvid.c_str(),dis); time_t tt = time(0); if (dis>CYaSetting::m_sys_setting.rear_end_d ||!rear_end_arg_algo(u1,u2)) { if (vinfo.backfired_start_time==0) vinfo.backfired_start_time=tt; vinfo.real_end_start_time=0; if (tt-vinfo.backfired_start_time>CYaSetting::m_sys_setting.rear_end_t) { log_info("vehicle_alarm_backfired_timeout %s,%u",vvid.c_str(),id); if(vinfo.is_alarm){ event_tool::instance()->handle_event(OT_CARD,ET_VEHICLE_REAR_END,id,CYaSetting::m_sys_setting.rear_end_d,dis,false,DT_COMMON,vvid); } it_cv = m_CloserVehicle.erase(it_cv); continue; } } else { vinfo.backfired_start_time =0; if (vinfo.real_end_start_time==0) vinfo.real_end_start_time=tt; if (tt-vinfo.real_end_start_time>CYaSetting::m_sys_setting.rear_end_t) { // debug_print_syslog(0,"vehicle_alarm_real_end_timeout %s",vvid.c_str()); if (!vinfo.is_alarm) { log_info("vehicle_alarm_real_end_timeout_exec %s,%u",vvid.c_str(),id); event_tool::instance()->handle_event(OT_CARD,ET_VEHICLE_REAR_END,id,CYaSetting::m_sys_setting.rear_end_d,dis,true,DT_COMMON,vvid); vinfo.is_alarm = true; } } } ++it_cv; } } double rear_end_collision_prevented_business::get_absolute_distance(uint64_t c1,uint64_t c2) { point pp1=m_map[c1]._p;point pp2=m_map[c2]._p; double arg1=m_map[c1]._arg;double arg2=m_map[c2]._arg; point p1(pp1.x,-pp1.y); point p2(pp2.x,-pp2.y); if (fabs(arg1-arg2)<1e-10) return p1.dist(p2); std::stringstream ss; std::vector v = card_path::inst().find_path(p1,p2); point pt = p1;double dis = 0; for (const auto & p:v) { dis += pt.dist(p); pt=p; } dis += pt.dist(p2); return dis; } bool rear_end_collision_prevented_business::rear_end_arg_algo(uint64_t u1,uint64_t u2) { point p_1=m_map[u1].last_p;point p_2=m_map[u2].last_p; double arg_1=m_map[u1]._arg;double arg_2=m_map[u2]._arg; line_v l_1=m_map[u1]._line;line_v l_2=m_map[u2]._line; std::string card1=tool_other::get_string_cardid(u1);std::string card2=tool_other::get_string_cardid(u2); if(p_1.empty() || p_2.empty()) return false; log_info("[vehicle_alarm_begin_algo]%s&%s %f,%f (%s)(%s)--(%.2f,%.2f)(%.2f,%.2f)",card1.c_str(),card2.c_str(),arg_1,arg_2,l_1.to_string().c_str(),l_2.to_string().c_str(),p_1.x,p_1.y,p_2.x,p_2.y); if (point::eq(arg_1,0x12345678,1e-10) || point::eq(arg_2,0x12345678,1e-10)) { log_info("[vehicle_alarm_invalid]%s&%s %f,%f",card1.c_str(),card2.c_str(),arg_1,arg_2); return false; } if (!point::eq(arg_1,0,1e-10)) if (fabs(fabs(arg_1-arg_2)-3.141593)< 0.000005) { log_info("[vehicle_alarm_opposite]%s&%s",card1.c_str(),card2.c_str()); return false; } if (point::eq(arg_1,arg_2,1e-10)) { double arg = std::arg(std::complex(p_1.x,p_1.y)-std::complex(p_2.x,p_2.y)); if (!(fabs(fabs(arg)-fabs(arg_1))<1e-10 || fabs(fabs(arg)+fabs(arg_2)-3.141593)< 0.000005)) { log_info("[vehicle_alarm_parallel]%s&%s %f,%f()",card1.c_str(),card2.c_str(),arg,arg_1); return false; } } if(!point::eq(arg_1,arg_2,1e-10)) { point p = l_1.line::crossing(l_2); if (p==l_1[1] || p==l_2[1]) { log_info("[vehicle_alarm_point]%s&%s",card1.c_str(),card2.c_str()); return true; } double arg1 = std::arg(std::complex(p.x,p.y)-std::complex(l_1[1].x,l_1[1].y)); double arg2 = std::arg(std::complex(p.x,p.y)-std::complex(l_2[1].x,l_2[1].y)); if (fabs(fabs(arg1-arg_1)-3.141593)<0.000005 && fabs(fabs(arg2-arg_2)-3.141593)<0.000005) { log_info(0,"[vehicle_alarm_backfired]%s&%s",card1.c_str(),card2.c_str()); return false; } } log_info("[vehicle_alarm_end]%s&%s %f,%f",card1.c_str(),card2.c_str(),arg_1,arg_2); return true; }