ruleserver/ruleToformula.go
@@ -1,7 +1,7 @@
package ruleserver
import (
   "encoding/json"
   "fmt"
   "ruleprocess/cache"
   "ruleprocess/logger"
   "sort"
@@ -9,56 +9,9 @@
   "strings"
   "time"
   bigCache "basic.com/pubsub/cache.git"
   "basic.com/pubsub/cache.git/esutil"
   "basic.com/pubsub/protomsg.git"
   "github.com/knetic/govaluate"
)
func init() {
   bigCache.Init()
}
// 任务
type Task struct {
   camID     string //摄像机ID
   taskID    string //任务ID
   sdkID     string //算法ID
   areaId    string //区域id
   areaName  string //区域名称
   topicType string //规则主题类型,目标/持续时间/灵敏度等
}
// 数据库中的规则元素
type SingleRule struct {
   Task
   operatorType     string // 操作符,>=,==...
   compareType      string // 对比类型,值,被选项
   compareValue     string // 对比的值
   ruleWithPrevious string // 跟上一条的逻辑关系
   groupId          string // 大规则id
}
// 数据库中单条子规则  跟数据库映射的
type CameraTaskArg struct {
   Id               string `json:"id"`
   CameraTaskId     string `json:"camera_task_id"`
   CameraId         string `json:"camera_id"`
   PolygonId        string `json:"polygon_id"`
   SdkId            string `json:"sdk_id"`
   SdkArgAlias      string `json:"sdk_arg_alias"`
   Operator         string `json:"operator"`      //操作符,>=,==...
   OperatorType     string `json:"operator_type"` //对比类型,值,被选项
   SdkArgValue      string `json:"sdk_arg_value"` //对比的值
   Sort             int    `json:"sort"`
   RuleWithPrevious string `json:"rule_with_previous"` //跟上一条的逻辑关系
   GroupId          string `json:"group_id"`           //大规则id
}
// sdk输出的图片提取参数数据之后的数据集合,也是传给下一步用于赋值的数据集合
type AreaMapList struct {
   areaMapList []AreaMap
}
// 每个目标的参数:相似度,占比,尺寸
type Arg struct {
@@ -70,11 +23,6 @@
   Feature    []byte
   ThftRes    protomsg.ThftResult
   Liker      []*protomsg.Baseinfo
}
type LikePerson struct {
   Id    string  // 与之相似的底库人员的id
   Score float64 // 与底库人员的相似值
}
// 每个区域内的图片数据集合
@@ -89,8 +37,8 @@
   triggerLine   string
   directionLine string
   targetNum     int    // 区域内目标数量
   args          []Arg  // 区域内目标集合
   filterData    []Arg  // 过滤后区域内目标集合
   args          []*Arg // 区域内目标集合
   filterData    []*Arg // 过滤后区域内目标集合
   time          string // 当前时间(用以匹配时间规则)
   keepRight     bool   // 是否靠右行
   isStatic      bool   // 是否静止
@@ -115,32 +63,30 @@
   IsStatic    bool       // 是否静止
   ImageWidth  int        // 摄像机拍摄的图像宽 像素
   ImageHeight int        // 摄像机拍摄的图像高 像素
   AreaMapList []AreaMap  // 本sdk提取的数据按照区域划分后的数据集合
   AreaMapList []*AreaMap // 本sdk提取的数据按照区域划分后的数据集合
}
// 从算法模块儿拿来的对一帧图像各个算法提取的数据集合
type SdkDatas struct {
   CameraId   string
   Sdkdata    []*SdkData
   RuleResult map[string]interface{} // 过完规则后打的标签 face: []Arg  yolo: []Result
   RuleResult map[string]interface{} // 过完规则后打的标签 face: []Arg, yolo: []Result, cacheData: SdkDatas, timeLabel: 0,1,2,3,4,5
}
// 将传递过来的参数转化为
//protomsg.SdkMessage.TaskLabel.SdkmsgWithTask.sdkdata
type ResultMsg struct {
   protomsg.SdkMessage
   *protomsg.SdkMessage
   RuleResult map[string]interface{} // 过完规则后打的标签
}
// 过规则库打上的标签
type Result struct {
   TaskId      string // 任务id
   SdkName     string
   RuleGroupId string // 规则组id
   AlarmLevel  int32  // 报警等级
   RuleText    string // 文字版规则组
   Location    []Rect
   TaskId       string // 任务id
   SdkName      string
   RuleGroupId  string // 规则组id
   AlarmLevel   int32  // 报警等级
   RuleText     string // 文字版规则组
   Location     []Rect // 目标的坐标
   AlarmPolygon string // 触发的报警框
}
type LittleRuleResult struct {
   SdkName string // 记录下此结果是哪个sdk的结果
@@ -148,44 +94,8 @@
   Sort    int32
}
//
type Face struct {
   Location Rect // 人脸坐标框
   SdkName  string
   ThftRes  protomsg.ThftResult
   Liker    []LikePerson // 相似人员(如果是单纯的人脸检测可无此项)
}
// 包含N条规则元素的一整条规则
type CompleteRule struct {
   rule string
}
// 根据摄像机id拿到摄像机所有区域
func GetPolygons(cameraId string) []protomsg.CameraPolygon {
   var cameraPolygons []protomsg.CameraPolygon
   cameraPolygons = cache.GetPolygonsByCameraId(cameraId)
   return cameraPolygons
}
// 把sdk从数据帧上提取的按照区域分类归置
func SdkDataFormat(cameraId string, arg *SdkData, cameraPolygons []protomsg.CameraPolygon) {
   logger.Info("==================================本sdkData中解出来的目标数据=======================================")
   for _, photo := range arg.Photo {
      logger.Info("--------看看解析出来的数据---", cameraId, arg.IpcId, photo.Rects, photo.Score)
   }
   for _, polygon := range cameraPolygons {
      //logger.Println("++++++在这儿看一下区域啊:", polygon.Polygon)
      areaMap := AreaMap{cameraId: cameraId, areaId: polygon.Id, areaJson: polygon.Polygon, triggerLine: polygon.TriggerLine, directionLine: polygon.DirectionLine}
      // 为每个摄像机区域填充数据
      areaMap.CountAreaObjs(arg)
      arg.AreaMapList = append(arg.AreaMapList, areaMap)
   }
}
// 对单帧图像的判断 thisSdkDatas  当前传入的这帧数据,cacheSdkData 定时器里缓存的一帧数据 没有就返回nil  (thisSdkDatas SdkDatas, cacheSdkDatas SdkDatas)
func Judge(args *SdkDatas) {
func Judge(args *SdkDatas,message *protomsg.SdkMessage) {
   if len(args.Sdkdata) > 0 {
      // 拿到本摄像机的区域
      cameraPolygons := GetPolygons(args.CameraId)
@@ -211,10 +121,10 @@
               if len(temp) > 0 {
                  if ruleList[i].SetType == "linkTask" {
                     // groupId中含有link则为联动任务
                     LinkTask(args, ruleList[i], taskId)
                     LinkTask(args, ruleList[i], taskId,message)
                  } else {
                     // 独立任务的处理
                     RunRule(args, ruleList[i], taskId)
                     RunRule(args, ruleList[i], taskId,message)
                  }
               }
            }
@@ -222,83 +132,8 @@
      }
   }
}
func Compare(args *SdkDatas, groupRule *protomsg.GroupRule) {
   compareFlag := 0
   tableIds := ""
   // 看看是否有只配人脸比对算法但没有配对比库的规则,如果有,则比对对象为全部底库
   for j := 0; j < len(groupRule.Rules); j++ {
      if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" { // 配了人脸比对
         if groupRule.Rules[j].SdkArgAlias == "compareBase" && groupRule.Rules[j].SdkArgValue != "" { // 配了比对底库的参数但没有配全部底库
            compareFlag = 2
            tableIds = groupRule.Rules[j].SdkArgValue + "," // 最后会多一个tableId,切出来的数组取len-1就可以
         }
         if groupRule.Rules[j].SdkArgAlias == "compareBase" && groupRule.Rules[j].SdkArgValue == "" { // 配的参数是比对全部底库
            compareFlag = 1
         }
      }
   }
   // 为了测试作下弊,直接让其比对全部底库
   compareFlag = 1
   if compareFlag == 0 {
      logger.Info("没有配置对比底库参数")
      return
   }
   for j := 0; j < len(groupRule.Rules); j++ {
      if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
         for _, sdkData := range args.Sdkdata {
            if sdkData.IpcId == "A8B73405-373D-4F23-CED2-A617EBD7EC55" { // 搜索到人脸检测的sdkdata 现在关于人脸的只有他一个sdk,全找他
               logger.Info("============================================第一关")
               for _, areaMap := range sdkData.AreaMapList {
                  // 拿区域中每个人脸特征值去对比,填充其liker
                  if groupRule.Rules[j].PolygonId == areaMap.areaId {
                     for _, arg := range areaMap.args {
                        if compareFlag == 1 {
                           bytes := bigCache.Getdbpersonmsg("", arg.Feature, true)
                           var m map[string]float32
                           err1 := json.Unmarshal(bytes, &m)
                           if err1 != nil {
                              logger.Error("getBaseInfo解压错误", err1)
                           }
                           logger.Info("----------------------------------------map是", m)
                           for key, val := range m {
                              logger.Info("_______________________________________对比库的返回值", key, val)
                              baseinfo, err1 := esutil.Dbpersoninfosbyid(key)
                              if err1 != nil {
                                 logger.Error("查询底库人员信息出错", err1)
                              }
                              baseinfo.CompareScore = val * 100
                              arg.Liker = append(arg.Liker, &baseinfo)
                           }
                        }
                        if compareFlag == 2 {
                           array := strings.Split(tableIds, ",")
                           for i := 0; i < len(array)-1; i++ {
                              bytes := bigCache.Getdbpersonmsg(array[i], arg.Feature, true)
                              var m map[string]float32
                              err1 := json.Unmarshal(bytes, &m)
                              if err1 != nil {
                                 logger.Error("getBaseInfo解压错误", err1)
                              }
                              for key, val := range m {
                                 baseinfo, err1 := esutil.Dbpersoninfosbyid(key)
                                 if err1 != nil {
                                    logger.Error("查询底库人员信息出错", err1)
                                 }
                                 baseinfo.CompareScore = val
                                 arg.Liker = append(arg.Liker, &baseinfo)
                              }
                           }
                        }
                        logger.Info("-------------------成功给liker赋值:", arg.Liker)
                     }
                  }
               }
            }
         }
      }
   }
}
func RunRule(args *SdkDatas, groupRule *protomsg.GroupRule, taskId string) bool {
func RunRule(args *SdkDatas, groupRule *protomsg.GroupRule, taskId string,message *protomsg.SdkMessage) bool {
   defer func() {
      if err := recover(); err != nil {
         logger.Error("比对规则有误", err.(string))
@@ -308,6 +143,7 @@
   Compare(args, groupRule)
   resultSplice := []*LittleRuleResult{}
   sdkNames := ""
   polygonId := ""
   // 先过完条件规则
   for j := 0; j < len(groupRule.Rules); j++ {
      for _, sdkData := range args.Sdkdata {
@@ -318,16 +154,24 @@
         }
         ipcId := sdk.IpcId
         sdkName := sdk.SdkName
         logger.Info("规则的ipcId与sdkData的IpcId:", ipcId, "===", sdkData.IpcId)
         if ipcId == sdkData.IpcId {
            logger.Info("当前走的规则的算法是--:", sdkName, "---")
            logger.Info("========================有几个区域:",len(sdkData.AreaMapList))
            for _,areaMap := range sdkData.AreaMapList{
               logger.Info("检查一下区域的具体数据:",areaMap.areaJson)
            }
            for _, areaMap := range sdkData.AreaMapList {
               ruleResult := filterRule(groupRule.Rules[j], &areaMap)
               ruleResult := filterRule(groupRule.Rules[j], areaMap)
               if ruleResult.Result != "" {
                  logger.Info("条件规则结果:", ruleResult.Result)
                  // 如果此结果为真且当前过的是yolo算法,应记下此规则所对应的sdkName,另外,还要去重
                  if ruleResult.Result == "true" && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                  // 如果此结果为真且当前过的是yolo算法,应记下此规则所对应的sdkName,另外,还要去重 (后加:把此条触碰的区域id也记录下来)
                  if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                     sdkNames = sdkName + ","
                     polygonId = groupRule.Rules[j].PolygonId + ","
                  }
                  if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                     polygonId = groupRule.Rules[j].PolygonId + ","
                  }
                  resultSplice = append(resultSplice, &ruleResult)
               }
@@ -348,11 +192,14 @@
         sdkName := sdk.SdkName
         if ipcId == sdkData.IpcId {
            for _, areaMap := range sdkData.AreaMapList {
               ruleResult := transferParameters(groupRule.Rules[j], &areaMap)
               ruleResult := transferParameters(groupRule.Rules[j], areaMap)
               if ruleResult.Result != "" {
                  logger.Info("数量规则结果:", ruleResult.Result)
                  if ruleResult.Result == "true" && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                  if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                     sdkNames = sdkName + ","
                  }
                  if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                     polygonId = groupRule.Rules[j].PolygonId + ","
                  }
                  resultSplice = append(resultSplice, &ruleResult)
               }
@@ -371,11 +218,14 @@
         sdkName := sdk.SdkName
         if ipcId == sdkData.IpcId {
            for _, areaMap := range sdkData.AreaMapList {
               ruleResult := timeRuleResult(groupRule.Rules[j], &areaMap)
               ruleResult := timeRuleResult(groupRule.Rules[j], areaMap)
               if ruleResult.Result != "" {
                  logger.Info("时间规则结果:", ruleResult.Result)
                  if ruleResult.Result == "true" && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                  if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                     sdkNames = sdkName + ","
                  }
                  if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                     polygonId = groupRule.Rules[j].PolygonId + ","
                  }
                  resultSplice = append(resultSplice, &ruleResult)
               }
@@ -383,22 +233,7 @@
         }
      }
   }
   // 最后过持续时间等时间维度的条件
   for j := 0; j < len(groupRule.Rules); j++ {
      for _, sdkData := range args.Sdkdata {
         sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
         if err != nil {
            logger.Error("没查到sdk的信息---", err)
         }
         ipcId := sdk.IpcId
         if ipcId == sdkData.IpcId {
            for _, areaMap := range sdkData.AreaMapList {
               // 去开启一个定时器
               duration(groupRule.Rules[j], groupRule.GroupId, &areaMap, args)
            }
         }
      }
   }
   // 将数组按sort排序
   sort.Sort(resultList(resultSplice))
   // 排序后取各自的结果和连接符拼出规则表达式得出结果
@@ -426,97 +261,85 @@
         panic("规则有误,得到的数学公式不可解析")
      }
      result, _ := expression.Evaluate(nil) // 得到数学公式的结果
      if !result.(bool) {
         // 给这帧数据打上规则组标签
         //args.RuleResult = append(args.RuleResult, Result{TaskId: taskId, RuleGroupId: groupRule.GroupId})
         for k, timeEle := range TimeEleList {
            if strings.Contains(k, groupRule.GroupId) {
               timeEle.N = timeEle.InitN // 重置定时器
      if result.(bool) {
         // 最后成功报警才把符合条件的人脸数据塞进结果标签里
         // 配了人脸的算法才把人脸的数据甩出来打标签
         faces := []Arg{}
         faceFlag := false
         for j := 0; j < len(groupRule.Rules); j++ {
            if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
               faceFlag = true
            }
         }
         logger.Info("-------------------重置相关的定时器并返回false---------------")
         return false
      } else {
         // 判断持续时间条件,去看池子里是否有与本帧数据有关的定时器,如果有,看此时是否走到0,没有此定时器或有定时器走到0的话返回成功报警
         var flag bool = true
         for k, timeEle := range TimeEleList {
            if strings.Contains(k, groupRule.GroupId) {
               if timeEle.N != 0 { // 这组规则的定时器要全部等于0
                  logger.Info("———————————-------------不冤,你是被定时器打败的:")
                  flag = false
         for _, sdkData := range args.Sdkdata {
            if sdkData.IpcId == "A8B73405-373D-4F23-CED2-A617EBD7EC55" && faceFlag { // sdkData里有人脸数据且配置了算法才把符合条件的数据塞进标签里去
               for _, areaMap := range sdkData.AreaMapList {
                  faces = append(faces, putFaceToResult(areaMap)...)
               }
            }
         }
         if flag {
            // 最后成功报警才把符合条件的人脸数据塞进结果标签里
            // 配了人脸的算法才把人脸的数据甩出来打标签
            logger.Info("------------------------------最后一关")
            faces := []Arg{}
            faceFlag := false
            for j := 0; j < len(groupRule.Rules); j++ {
               if groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || groupRule.Rules[j].SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
                  faceFlag = true
         if faceFlag {
            args.RuleResult["face"] = faces
         }
         logger.Warn("___________________________________________________________________________终于走完万里长征")
         // 把他们的位置数据也传下去
         locations := []Rect{}
         for _, sdkData := range args.Sdkdata {
            if sdkData.IpcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && sdkNames != "" { // 把yolo数据的各个目标的坐标输出方便后面画框
               for _, areaMap := range sdkData.AreaMapList {
                  locations = append(locations, putYolosToResult(areaMap)...)
               }
            }
         }
         logger.Debug("------locations的内容:",locations)
         if sdkNames != "" {
            args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]Result), Result{taskId, sdkNames, groupRule.GroupId, groupRule.AlarmLevel, groupRule.GroupText, locations,polygonId})
            logger.Info("-------------------yolo结果标签长度", len(args.RuleResult["yolo"].([]Result)))
         }
         if args.RuleResult["face"] != nil {
            logger.Info("-------------------face结果标签", len(args.RuleResult["face"].([]Arg)))
         }
         // 最后过持续时间等时间维度的条件   把时间规则位置调整到这个位置是为了缓存数据
         for j := 0; j < len(groupRule.Rules); j++ {
            for _, sdkData := range args.Sdkdata {
               if sdkData.IpcId == "A8B73405-373D-4F23-CED2-A617EBD7EC55" && faceFlag { // sdkData里有人脸数据且配置了算法才把符合条件的数据塞进标签里去
               sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
               if err != nil {
                  logger.Error("没查到sdk的信息---", err)
               }
               ipcId := sdk.IpcId
               if ipcId == sdkData.IpcId {
                  for _, areaMap := range sdkData.AreaMapList {
                     faces = append(faces, putFaceToResult(&areaMap)...)
                     // 去开启一个定时器
                     duration(groupRule.Rules[j], groupRule.GroupId, areaMap, args,message)
                  }
               }
            }
            if faceFlag {
               args.RuleResult["face"] = faces
            }
            logger.Warn("___________________________________________________________________________终于走完万里长征")
            // 把他们的位置数据也传下去
            locations := []Rect{}
            for _, sdkData := range args.Sdkdata {
               if sdkData.IpcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && sdkNames != "" { // 把yolo数据的各个目标的坐标输出方便后面画框
                  for _, areaMap := range sdkData.AreaMapList {
                     locations = append(locations, putYolosToResult(&areaMap)...)
                  }
               }
            }
            if sdkNames != "" {
               args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]Result), Result{taskId, sdkNames, groupRule.GroupId, groupRule.AlarmLevel, groupRule.GroupText, locations})
               logger.Info("-------------------yolo结果标签", args.RuleResult["yolo"].([]Result))
            }
            if args.RuleResult["face"] != nil {
               logger.Info("-------------------face结果标签", args.RuleResult["face"].([]Arg))
            }
         }
         // 进行定时器的处理和判断
         timeFlag := TimerAlarm(args,groupRule.GroupId,result.(bool))
         if timeFlag == "01" || timeFlag == "10" || timeFlag == "11" { // 满足定时器条件
            return true
         } else {
            return false
         }
      } else {
         // 结果为假时也要走,有时候为假的状态反转数据也需要记录下来
         timeFlag := TimerAlarm(args,groupRule.GroupId,result.(bool))
         fmt.Println(timeFlag)
         return false
      }
   } else {
      return false
   }
}
func TimerAlarm(groupId string) (int){
   var flagTime int = 0
   for k, timeEle := range TimeEleList {
      if strings.Contains(k, groupId) {
         if timeEle.N == 0 && !timeEle.AlarmFlag { // 这组规则的定时器要全部等于0   暂且认为一组规则只有一个定时器
            logger.Info("———————————-------------首次符合持续时间规则并报警")
            flagTime = 1
            timeEle.AlarmFlag = true
         }
         if timeEle.N == 0 && timeEle.AlarmFlag {
            logger.Info("-------------------------符合持续时间规则但并不是首次,不报警")
            flagTime = 2
         }
      }
   }
   return flagTime
}
func putFaceToResult(am *AreaMap) []Arg {
   faces := []Arg{}
   if len(am.filterData) > 0 {
      for _, data := range am.filterData {
         faces = append(faces, data)
         faces = append(faces, *data)
      }
   }
@@ -535,60 +358,8 @@
   return locations
}
// 计算区域内的目标数量以及将相似度、占比、尺寸等打包
func (a *AreaMap) CountAreaObjs(arg *SdkData) {
   a.targetNum = 0
   threshold := 0.0       // 相似度
   intersectionper := 0.2 // 占比
   size := 0.0            // 尺寸
   areaPoints := Json2points(a.areaJson)
   widthScale := float64(arg.ImageWidth / 960)
   heigthScale := float64(arg.ImageHeight / 540)
   for _, obj := range arg.Photo {
      //logger.Info("------------------看看sdkData:", arg.SdkName, "的Photo数据----------------", obj, "----顺便看看占比-----:", PgsInterPercent(areaPoints, obj.Rects, widthScale, heigthScale))
      if threshold <= obj.Score && size <= float64(obj.Rects.Width*obj.Rects.Height) && intersectionper <= PgsInterPercent(areaPoints, obj.Rects, widthScale, heigthScale) {
         // 这步要备齐表达式里所需要的所有参数
         a.targetNum++
         arg1 := Arg{obj.Score, PgsInterPercent(areaPoints, obj.Rects, widthScale, heigthScale), float64(obj.Rects.Width * obj.Rects.Height), obj.IsYolo, obj.Rects, obj.Feature, obj.ThftRes, []*protomsg.Baseinfo{}}
         //logger.Println("放进去的arg:-------", arg1)
         a.args = append(a.args, arg1)
         a.filterData = append(a.filterData, arg1)
      }
   }
   a.time = time.Unix(time.Now().Unix(), 0).String()[11:16]
   a.keepRight = arg.KeepRight
   a.isStatic = arg.IsStatic
   //logger.Println("--------------------看看区域数据:",*a)
}
// 将字符串格式的坐标序列化为Point格式
func Json2points(areaPoints string) []Point {
   var pts []Point
   if areaPoints == "" {
      pts = append(pts, Point{0, 0})
      pts = append(pts, Point{0, 540})
      pts = append(pts, Point{960, 540})
      pts = append(pts, Point{960, 0})
   } else {
      err := json.Unmarshal([]byte(areaPoints), &pts)
      if err != nil {
         logger.Error("json.Unmarshal错误", err)
         panic("序列化坐标异常,程序退出")
      }
   }
   return pts
}
// 以摄像机id查出跟其相关的所有任务下的所有规则组
func GetRuleGroup(cameraId string) []*protomsg.TaskGroupArgs {
   all := cache.GetCameraTaskRulesByCameraId(cameraId)
   return all
}
// 联动任务的处理
func LinkTask(args *SdkDatas, groupRule *protomsg.GroupRule, taskId string) {
func LinkTask(args *SdkDatas, groupRule *protomsg.GroupRule, taskId string,message *protomsg.SdkMessage) {
   // new一个定时器,如果以此groupId为标志的定时器不存在的话
   logger.Info("------------------------------------------当前是联动任务,规则是:", groupRule.GroupText)
   var flag bool = true
@@ -618,7 +389,7 @@
      }
   }
   // 往数组里赋值
   isOk := RunRule(args, groupRule, taskId)
   isOk := RunRule(args, groupRule, taskId,message)
   if isOk {
      logger.Info("这帧图像在任务下的一整条规则下(联动任务下就是跟本摄像机像相关的小规则)的判断结果为true")
      // 根据cameraId去更新或者插入结果,然后判断是否数组是否可以得出报警的结论
@@ -651,7 +422,7 @@
            result, _ := expression.Evaluate(nil) // 得到数学公式的结果
            if result.(bool) {
               logger.Info("___________________________________________________________________联动任务报警")
               args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]Result), Result{taskId, "", groupRule.GroupId, groupRule.AlarmLevel, groupRule.GroupText, []Rect{}})
               args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]Result), Result{taskId, "", groupRule.GroupId, groupRule.AlarmLevel, groupRule.GroupText, []Rect{},""})
               logger.Info("-------------------yolo结果标签有几个", len(args.RuleResult["yolo"].([]Result)))
               if args.RuleResult["face"] != nil {
                  logger.Info("-------------------face结果标签有几个", len(args.RuleResult["face"].([]Arg)))
@@ -681,8 +452,7 @@
      //logger.Info("规则的算法id和区域的算法id:", rule.SdkId, "===", am.sdkId)
      if rule.PolygonId == am.areaId { // 算法和区域都得对的上
         if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a972" && rule.SdkArgAlias != "time_rule" {
            // 只需要过滤阈值,过滤完后数组长度大于0即为报警,但要考虑如何对每一张都报警呢
         if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a972" && rule.SdkArgAlias != "time_rule" && rule.SdkArgAlias != "compareBase"{
            argValue, err := strconv.ParseFloat(rule.SdkArgValue, 64)
            if err != nil {
               logger.Error("规则配置的阈值非法")
@@ -692,7 +462,7 @@
            for _, obj := range am.filterData {
               for index := 0; index < len(obj.Liker); {
                  // 将达不到阈值的相似者从相似者数组中删除
                  logger.Warn("=======================相似值:", float64(obj.Liker[index].CompareScore*100))
                  logger.Debug("=======================相似值:", float64(obj.Liker[index].CompareScore*100))
                  if float64(obj.Liker[index].CompareScore*100) < argValue {
                     // Go 语言中切片删除元素的本质是:以被删除元素为分界点,将前后两个部分的内存重新连接起来。不用怀疑,数组删除元素就这么坑爹
                     obj.Liker = append(obj.Liker[:index], obj.Liker[index+1:]...)
@@ -717,12 +487,11 @@
            return LittleRuleResult{am.sdkName, rule.RuleWithPre + "" + flag, rule.Sort}
         }
         if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" { // 人脸检测
            logger.Info("------------------------------------------------------------------------------------------------------------------------------------终于等到你")
            if rule.Operator == "==" || rule.Operator == ">=" || rule.Operator == "<=" || rule.Operator == "<" || rule.Operator == ">" || rule.Operator == "!=" {
               // 如果是不规矩的连接符统统返回false 规则也只能判断人脸的相似度,所以不存在别的连接符
               if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
                  logger.Info("--------------------终于等到你的下文")
                  var args []Arg
                  //logger.Info("---------------------------终于等到你")
                  var args []*Arg
                  if rule.RuleWithPre == "&&" {
                     args = am.filterData
                  } else {
@@ -730,7 +499,7 @@
                  }
                  // 先清空过滤后的数据,再往里塞本次过滤后的数据
                  am.filterData = am.filterData[0:0]
                  //logger.Info("-----------------------人脸过滤的args:", args)
                  //logger.Info("-----------------------人脸过滤的args里的数量:", len(args))
                  for _, arg := range args {
                     var formula string
                     if rule.SdkArgAlias == "score" {
@@ -771,7 +540,7 @@
      if rule.PolygonId == am.areaId { // 首先这条规则得是这个算法的规则,其次规则所对应的区域id要跟区域数据的id对的上
         if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
            logger.Info("----------当前条件规则:---------", rule)
            var args []Arg
            var args []*Arg
            if rule.RuleWithPre == "&&" {
               args = am.filterData
            } else {
@@ -779,6 +548,7 @@
            }
            // 先清空过滤后的数据,再往里塞本次过滤后的数据
            am.filterData = am.filterData[0:0]
            logger.Debug("看看args:::::",args)
            for _, arg := range args {
               var formula string
               if rule.SdkArgAlias == "score" {
@@ -815,7 +585,7 @@
}
// 如果有持续时间条件维护开启一个定时器
func duration(rule *protomsg.Rule, groupId string, am *AreaMap, args *SdkDatas) {
func duration(rule *protomsg.Rule, groupId string, am *AreaMap, args *SdkDatas,message *protomsg.SdkMessage) {
   if rule.PolygonId == am.areaId { // 首先规则所对应的区域id要跟区域数据的id对的上  配置的算法要对的上
      if rule.SdkArgAlias == "duration" { //
         // 先看看定时器元素队列中是否有这个摄像机这个区域的定时器,如果有就不能再次创建了
@@ -829,7 +599,7 @@
         if flag {
            timeLength, _ := strconv.Atoi(rule.SdkArgValue)
            timeEle := TimeElement{N: timeLength, InitN: timeLength, AlarmFlag: false, CacheSdkData: *args} // 扔进去一个定时器元素(并缓存当前画面帧数据)
            timeEle := TimeElement{N: timeLength, InitN: timeLength, AlarmFlag: false,BufferFlag:10, CacheSdkData: ResultMsg{message,args.RuleResult}} // 扔进去一个定时器元素(并缓存当前画面帧数据)
            //TimeEleList = make(map[string]timeElement)
            TimeEleList[groupId+" "+rule.Id] = &timeEle // 定时器元素以摄像机id拼接区域id为键
            logger.Info("创建了计数器并且计数器集合为:", TimeEleList)
@@ -931,39 +701,4 @@
   return LittleRuleResult{}
}
// 根据传入的字符串得到其在一周内的索引 周一到周日分别对应1到7
func getIndexOfWeek(weekday string) int {
   var weekdays = [7]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
   for k, value := range weekdays {
      if value == weekday {
         return k + 1 // 因为数据库中存的是1-7代表的周一到周日
      }
   }
   return 0
}
type TimeRange struct {
   Start string `json:"start"`
   End   string `json:"end"`
}
type day struct {
   Day       int         `json:"day"`        // 标示当前星期几
   TimeRange []TimeRange `json:"time_range"` // 当天的几个时间段
}
// 取出某个时间规则的第几天的规则段集合
func GetTimeById(id string, index int) []TimeRange {
   _, cameraTimeRule := cache.GetTimeRuleById(id)
   var timeRangeList []day
   err := json.Unmarshal([]byte(cameraTimeRule.TimeRule), &timeRangeList)
   if err != nil {
      logger.Error("取时间规则时反序列化错误!")
   }
   for _, timerange := range timeRangeList {
      if timerange.Day == index {
         //logger.Println("取到的时间规则:", timerange.TimeRange)
         return timerange.TimeRange
      }
   }
   return nil
}