panlei
2019-10-31 355284a3ac944515951d4c2a7ec5d3964fb13857
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
package ruleserver
 
import (
    "ruleprocess/cache"
    "ruleprocess/structure"
    "basic.com/valib/logger.git"
    "sort"
    "strconv"
    "strings"
    "sync"
    "time"
 
    "basic.com/pubsub/protomsg.git"
    "github.com/knetic/govaluate"
)
 
var rw sync.RWMutex // 读写锁
 
// 对单帧图像的判断 thisSdkDatas  当前传入的这帧数据,cacheSdkData 定时器里缓存的一帧数据 没有就返回nil  (thisSdkDatas SdkDatas, cacheSdkDatas SdkDatas)
func Judge(args *structure.SdkDatas, message *protomsg.SdkMessage) {
    defer func() {
        if err := recover(); err != nil {
            logger.Error("规则模块儿的异常捕获:",err)
        }
    }()
    if len(args.Sdkdata) > 0 {
        // 拿到本摄像机的区域
        cameraPolygons := GetPolygons(args.CameraId)
        // 把所有的sdk提取的数据都按所属摄像机的区域归置
        logger.Debug("当前摄像机id为:",message.Cid,"当前摄像机执行的任务是:",message.Tasklab.Taskname,"--任务id为:",message.Tasklab.Taskid)
        for _, arg := range args.Sdkdata {
            SdkDataFormat(args.CameraId, arg, cameraPolygons)
        }
        // 跑本摄像机的所有规则组 一组一组跑
        taskGroup := GetRuleGroup(args.CameraId, args.TaskId) // 本摄像机本任务下所有规则组
        //logger.Println("看下摄像机下的任务组:",taskRuleList)
        // 得到属于该摄像机的若干组任务的完整规则(跟每一条完整规则比较之后得出本张图像对于某个规则是否报警的结果。放进map,比如本帧图像的id,所碰撞成功的规则id)
        args.RuleResult = make(map[string]interface{})
        args.RuleResult["yolo"] = []structure.Result{}
        args.RuleResult["face"] = []structure.FaceResult{}
        //logger.Warn("传进去之前是什么德行:",args.RuleResult["yolo"])
        if taskGroup != nil && len(taskGroup.GroupRules) > 0 {
            // 先过独立,再过联动
            for _, group := range taskGroup.GroupRules {
                //logger.Println("------------------------------任务规则:",taskRule)
                taskId := taskGroup.TaskId
                //logger.Println("------------本组任务下的规则组的数量:",len(ruleList))
                temp := group.Rules // temp为一组完整规则 在此需要判断规则是否是联动规则
                label := structure.Others{}
                if len(temp) > 0 {
                    if group.SetType != "linkTask" {
                        // 独立任务的处理
                        RunRule(args, group, taskId, message, label)
                    }
                }
            }
            for _, group := range taskGroup.GroupRules {
                //logger.Println("------------------------------任务规则:",taskRule)
                taskId := taskGroup.TaskId
                //logger.Println("------------本组任务下的规则组的数量:",len(ruleList))
                temp := group.Rules // temp为一组完整规则 在此需要判断规则是否是联动规则
                label := structure.Others{}
                if len(temp) > 0 {
                    if group.SetType == "linkTask" {
                        // groupId中含有link则为联动任务
                        LinkTask(args, group, taskId, message, label)
                    }
                }
            }
            // 人体追踪
            // 如果标签中含有持续时间首次报警的timeLabel的话则不需要过人体追踪,不然就没的插入了
            fk := TrackOrNot(args.RuleResult)
            if !fk {
                BodyIsSame(message)
            }
        }
    }
}
 
func RunRule(args *structure.SdkDatas, groupRule *protomsg.GroupRule, taskId string, message *protomsg.SdkMessage, label structure.Others) (bool,[]int) {
    defer func() {
        if err := recover(); err != nil {
            logger.Error("比对规则有误", err.(string))
        }
    }()
    logger.Info("+++++++++++规则开始运行+++++++++++++++++当前大规则--:", (*groupRule).GroupText)
    //logger.Warn("传进去之后是什么德行:",args.RuleResult["yolo"])
    Compare(args, groupRule)
    resultSplice := []*structure.LittleRuleResult{}
    sdkNames := ""
    polygonId := ""
    // 先过完条件规则
    for j := 0; j < len(groupRule.Rules); j++ {
        for _, sdkData := range args.Sdkdata {
            // 根据规则的sdkId查出其对应的ipcId,用ipcId去找该比对的数据
            sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
            if err != nil {
                logger.Error("没查到sdk的信息---", err)
            }
            ipcId := sdk.IpcId
            sdkName := sdk.SdkName
            //logger.Info("规则的ipcId与sdkData的IpcId:", ipcId, "===", sdkData.IpcId)
            if ipcId == sdkData.IpcId {
                //logger.Info("当前走的规则是--:", sdkName, "---","")
                for _, areaMap := range sdkData.AreaMapList {
                    ruleResult := filterRule(groupRule.Rules[j], areaMap)
                    if ruleResult.Result != "" {
                        logger.Info("条件规则结果:", ruleResult.Result)
                        // 如果结果为真,把这条规则中的区域置为有效
                        if strings.Contains(ruleResult.Result,"true") {
                            areaMap.IsEffective = true
                        }
                        // 如果此结果为真且当前过的是yolo算法,应记下此规则所对应的sdkName,另外,还要去重 (后加:把此条触碰的区域id也记录下来)
                        if strings.Contains(ruleResult.Result, "true") && ipcId == "02D54B61-0F16-C604-8567-FC4BE493C523" && !strings.Contains(sdkNames, sdkName) {
                            sdkNames = sdkName + " "
                        }
                        if strings.Contains(ruleResult.Result, "true") && !strings.Contains(polygonId, groupRule.Rules[j].PolygonId) {
                            polygonId = groupRule.Rules[j].PolygonId + " "
                        }
                        resultSplice = append(resultSplice, &ruleResult)
                    }
                }
            }
        }
    }
    // 再过其他数据 这步直接得到结果(真或假) 过目标数量
    for j := 0; j < len(groupRule.Rules); j++ {
        for _, sdkData := range args.Sdkdata {
            // 根据规则的sdkId查出其对应的ipcId,用ipcId去找该比对的数据
            sdk, err := cache.GetSdkById(groupRule.Rules[j].SdkId)
            if err != nil {
                logger.Error("没查到sdk的信息---", err)
            }
            ipcId := sdk.IpcId
            sdkName := sdk.SdkName
            if ipcId == sdkData.IpcId {
                for _, areaMap := range sdkData.AreaMapList {
                    ruleResult := transferParameters(groupRule.Rules[j], areaMap)
                    if ruleResult.Result != "" {
                        if strings.Contains(ruleResult.Result,"true") {
                            areaMap.IsEffective = true
                        }
                        logger.Info("数量规则结果:", ruleResult.Result)
                        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)
                    }
                }
            }
        }
    }
    // 这步过的是时间段规则(时间段等)
    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
            sdkName := sdk.SdkName
            if ipcId == sdkData.IpcId {
                for _, areaMap := range sdkData.AreaMapList {
                    ruleResult := timeRuleResult(groupRule.Rules[j], areaMap)
                    if ruleResult.Result != "" {
                        if strings.Contains(ruleResult.Result,"true") {
                            areaMap.IsEffective = true
                        }
                        logger.Info("时间规则结果:", ruleResult.Result)
                        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)
                    }
                }
            }
        }
    }
 
    // 将数组按sort排序
    sort.Sort(resultList(resultSplice))
    // 排序后取各自的结果和连接符拼出规则表达式得出结果
    completeFormula := ""
    for _, va := range resultSplice {
        completeFormula = completeFormula + va.Result
    }
    if strings.HasPrefix(completeFormula, "&&") || strings.HasPrefix(completeFormula, "||") || strings.HasPrefix(completeFormula, ">=") || strings.HasPrefix(completeFormula, "<=") || strings.HasPrefix(completeFormula, "==") || strings.HasPrefix(completeFormula, "!=") || strings.HasPrefix(completeFormula, ">") || strings.HasPrefix(completeFormula, "<") {
        // 以这些开头的基本是联动任务
        if strings.HasPrefix(completeFormula, "&&") || strings.HasPrefix(completeFormula, "||") || strings.HasPrefix(completeFormula, ">=") || strings.HasPrefix(completeFormula, "<=") || strings.HasPrefix(completeFormula, "==") || strings.HasPrefix(completeFormula, "!=") {
            completeFormula = completeFormula[2:]
        }
        if strings.HasPrefix(completeFormula, ">") || strings.HasPrefix(completeFormula, "<") {
            completeFormula = completeFormula[1:]
        }
        logger.Info("-------------------看看拔毛后的表达式:", completeFormula)
        //expression, _ := govaluate.NewEvaluableExpression(completeFormula)
        //result, _ := expression.Evaluate(nil) // 得到数学公式的结果
        //return result.(bool)
    }
    if completeFormula != "" {
        logger.Info("结果公式-----------:", completeFormula)
        expression, err2 := govaluate.NewEvaluableExpression(completeFormula)
        if strings.HasPrefix(completeFormula, "&&") || strings.HasPrefix(completeFormula, "||") || err2 != nil {
            panic("规则有误,得到的数学公式不可解析")
        }
        result, _ := expression.Evaluate(nil) // 得到数学公式的结果
 
        if result.(bool) {
            // 最后过持续时间等时间维度的条件   把时间规则位置调整到这个位置是为了缓存数据
            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, message)
                        }
                    }
                }
            }
            // 进行定时器的处理和判断
            timeFlag := TimerAlarm(&label, groupRule.GroupId, result.(bool))
            if timeFlag == "01" || timeFlag == "10" || timeFlag == "11" { // 没有定时器或者满足定时器条件
                // 打人脸标签和yolo标签
                // 最后成功报警才把符合条件的人脸数据塞进结果标签里
                // 配了人脸的算法才把人脸的数据甩出来打标签
                faces := []structure.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
                    }
                }
                for _, sdkData := range args.Sdkdata {
                    if sdkData.IpcId == "A8B73405-373D-4F23-CED2-A617EBD7EC55" && faceFlag { // sdkData里有人脸数据且配置了算法才把符合条件的数据塞进标签里去
                        for _, areaMap := range sdkData.AreaMapList {
                            if areaMap.IsEffective {
                                faces = append(faces, putFaceToResult(areaMap, faces)...)
                            }
                        }
                    }
                }
                logger.Info("face标签的长度:",len(faces))
                //for _,face := range faces  {
                //    //logger.Debug("————————————————________________看看人脸的坐标:",face.Location)
                //}
                logger.Warn("___________________________________________________________________________终于走完万里长征")
                // 把他们的位置数据也传下去
                locations := []structure.TargetInfo{}
                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)
                var islink bool
                if groupRule.SetType == "linkTask" {
                    islink = true
                } else {
                    islink = false
                }
                var labelTypes []int // 0为yolo标签,1为face标签 2为两者标签
                if sdkNames != "" {
                    args.RuleResult["yolo"] = append(args.RuleResult["yolo"].([]structure.Result), structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, locations, polygonId, islink,label,})
                    labelTypes = append(labelTypes,0)
                    //logger.Info("-------------------yolo结果标签长度", len(args.RuleResult["yolo"].([]Result)))
                }
                if faceFlag {
                    args.RuleResult["face"] = append(args.RuleResult["face"].([]structure.FaceResult), structure.FaceResult{structure.Result{taskId, sdkNames, groupRule.GroupId, groupRule.DefenceState, groupRule.AlarmLevel, groupRule.GroupText, []structure.TargetInfo{}, polygonId, islink,label,}, faces})
                    //logger.Info("-------------------face结果标签", len(args.RuleResult["face"].([]FaceResult)))
                    labelTypes = append(labelTypes,1)
                }
                return true,labelTypes
            } else {
                return false,[]int{}
            }
 
        } else {
            // 结果为假时也要走,有杀死定时器的操作
            TimerAlarm(&label, groupRule.GroupId, result.(bool))
            //fmt.Println(timeFlag)
            return false,[]int{}
        }
    } else {
        return false,[]int{}
    }
}
 
func putFaceToResult(am *structure.AreaMap, faceList []structure.Arg) []structure.Arg {
    faces := []structure.Arg{}
    if len(am.FilterData) > 0 {
        for _, data := range am.FilterData {
            flag := true
            for _, face := range faceList {
                if data.Location.X == face.Location.X && data.Location.Y == face.Location.Y && data.Location.Width == face.Location.Width && data.Location.Height == face.Location.Height {
                    flag = false
                }
            }
            if flag {
                faces = append(faces, *data)
            }
        }
    }
    //logger.Println("-----------------------------------------------听说你是空的?",faces)
    return faces
}
 
func putYolosToResult(am *structure.AreaMap) []structure.TargetInfo {
    locations := []structure.TargetInfo{}
    if len(am.FilterData) > 0 {
        for _, data := range am.FilterData {
            location := structure.TargetInfo{}
            location.Rect = data.Location
            location.TargetId = data.Id
            location.TargetScore = data.Score
            locations = append(locations, location)
        }
    }
    //logger.Println("-----------------------------------------------听说你是空的?",faces)
    return locations
}
 
// 联动任务的处理
func LinkTask(args *structure.SdkDatas, groupRule *protomsg.GroupRule, taskId string, message *protomsg.SdkMessage, label structure.Others) {
    // new一个定时器,如果以此groupId为标志的定时器不存在的话
    logger.Info("------------------------------------------当前是联动任务,规则是:", groupRule.GroupText)
    var flag bool = true
    var timeEle = TimeElement{N: 2, InitN: 2, GroupId: groupRule.GroupId}
    rw.Lock()
    for k, timeEle1 := range TimeEleList {
        if k == groupRule.GroupId {
            flag = false // 已经有了这个定时器就置为false 不再新增
            timeEle = *timeEle1
        }
    }
    for _,ruleRe := range timeEle.RuleResults {
        logger.Info("联动数组里的数据----",ruleRe.CameraId,ruleRe.Sort)
    }
    if flag { // 如果还没有这个定时器元素就新增一个
        //timeEle := TimeElement{N: 2, InitN: 2, GroupId: groupRule.GroupId} // 扔进去一个定时器元素
        //TimeEleList = make(map[string]timeElement)
        TimeEleList[groupRule.GroupId] = &timeEle // 定时器元素以规则组id为键
        logger.Info("---------------------------------------------联动任务创建了计数器并且计数器集合为:", TimeEleList)
        // 得出这组完整规则里涉及到几个摄像机,决定着数组里有几个结构体,去重添加方式
        for j := 0; j < len(groupRule.Rules); j++ {
            var flag1 bool = true
            logger.Info("规则组信息:",groupRule.Rules[j].CameraId)
            for _, ruleRes := range TimeEleList[groupRule.GroupId].RuleResults {
                logger.Info("联动数组里的数据:",ruleRes.CameraId,ruleRes.Sort)
                if groupRule.Rules[j].CameraId == ruleRes.CameraId {
                    flag1 = false
                }
            }
            if flag1 {
                TimeEleList[groupRule.GroupId].RuleResults = append(TimeEleList[groupRule.GroupId].RuleResults, &RuleResult{groupRule.Rules[j].CameraId, groupRule.Rules[j].Sort, "", groupRule.Rules[j].RuleWithPre, structure.ResultMsg{}})
            }
        }
    }
    rw.Unlock()
    // 往数组里赋值
    isOk,labelTypes := RunRule(args, groupRule, taskId, message, label)
    if isOk {
        logger.Info("这帧图像在任务下的一整条规则下(联动任务下就是跟本摄像机像相关的小规则)的判断结果为true")
        // 根据cameraId去更新或者插入结果,然后判断是否数组是否可以得出报警的结论
        // 往联动任务的结果数组里放值或更新
        for _, va := range timeEle.RuleResults {
            if va.CameraId == args.CameraId {
                va.Result = strconv.FormatBool(isOk)
                tempMap := make(map[string]interface{})
                for k, result := range args.RuleResult {
                    if k == "yolo" {
                        tempMap[k] = []structure.Result{}
                        for _, res := range result.([]structure.Result) {
                            tempMap[k] = append(tempMap[k].([]structure.Result), res)
                        }
                    }
                    if k == "face" {
                        tempMap[k] = []structure.FaceResult{}
                        for _, res := range result.([]structure.FaceResult) {
                            tempMap[k] = append(tempMap[k].([]structure.FaceResult), res)
                        }
                    }
                }
                va.CacheData = structure.ResultMsg{message, tempMap}
                logger.Info("这个摄像机--", args.CameraId, "--被赋予了result", va.Result)
            }
        }
        // 判断结果数组是否完满(即被赋值完毕)可得出报警结果
        var isPerfect = true
        for _, va := range timeEle.RuleResults {
            //logger.Info("---------------------瞅瞅当前数组________________:", *va)
            if va.Result == "" && va.RuleWithPre != "||" {
                isPerfect = false
            }
        }
        if isPerfect {
            logger.Debug("数组完满了,联动任务可以成功报警了!")
            // 将数组按sort排序
            sort.Sort(SubList(timeEle.RuleResults))
            // 排序后取各自的结果和连接符拼出规则表达式得出结果
            completeFormula := ""
            for _, va := range timeEle.RuleResults {
                completeFormula = completeFormula + va.RuleWithPre + "" + va.Result
            }
            logger.Info("---------------------------联动任务的公式", completeFormula)
            if completeFormula != "" {
                expression, _ := govaluate.NewEvaluableExpression(completeFormula)
                result, _ := expression.Evaluate(nil) // 得到数学公式的结果
                if result.(bool) {
                    logger.Info("___________________________________________________________________联动任务报警")
                    rw.RLock()
                    if TimeEleList[groupRule.GroupId] != nil {  // 极偶尔有情况会等于nil,不知道为啥,做个判断以防宕机
                        // 把数组里缓存的数据取出来一起报警
                        label.LinkCache = []structure.ResultMsg{}
                        for _, ruleRes := range TimeEleList[groupRule.GroupId].RuleResults {
                            label.LinkCache = append(label.LinkCache, ruleRes.CacheData)
                        }
                        logger.Debug("联动任务缓存了几个数据", len(label.LinkCache))
                        for i := 0; i < len(args.RuleResult["yolo"].([]structure.Result)); i++ {
                            if args.RuleResult["yolo"].([]structure.Result)[i].RuleGroupId == groupRule.GroupId { // 把联动数据追加上
                                args.RuleResult["yolo"].([]structure.Result)[i].Others.LinkCache = label.LinkCache
                            }
                        }
                        for i := 0; i < len(args.RuleResult["face"].([]structure.FaceResult)); i++ {
                            if args.RuleResult["face"].([]structure.FaceResult)[i].RuleGroupId == groupRule.GroupId { // 把联动数据追加上
                                args.RuleResult["face"].([]structure.FaceResult)[i].Others.LinkCache = label.LinkCache
                            }
                        }
                    }
                    rw.RUnlock()
                }
            }
        } else {
            logger.Warn("数组不圆满不打标签")
            // 倒是把打的组规则标签给去掉了啊
            for _,val := range labelTypes {
                if val == 0 {
                    if len(args.RuleResult["yolo"].([]structure.Result)) >= 1 {
                        lens := len(args.RuleResult["yolo"].([]structure.Result))-1
                        args.RuleResult["yolo"] = args.RuleResult["yolo"].([]structure.Result)[0:lens]
                    }
                }
                if val == 1 {
                    if len(args.RuleResult["face"].([]structure.FaceResult)) >= 1 {
                        lens := len(args.RuleResult["face"].([]structure.FaceResult))-1
                        args.RuleResult["face"] = args.RuleResult["face"].([]structure.FaceResult)[0:lens]
                    }
                }
            }
 
 
        }
    } else { // 没有报警,
        //logger.Info("这帧图像在任务下的一整条规则下(联动任务下就是跟本摄像机像相关的小规则)的判断结果为false")
        // 所以也要去结果数组里放值或更新   07/30备注:  不应放值,应删除定时器,等为true时再度开启
        //for _, va := range timeEle.RuleResults {
        //    if args.CameraId != "" && va.CameraId == args.CameraId {
        //        va.Result = strconv.FormatBool(isOk)
        //    }
        //}
        rw.Lock()
        for k, _ := range TimeEleList {
            if k == groupRule.GroupId {
                delete(TimeEleList, k)
                logger.Debug("因为定时器的一帧数据结果为false,干掉定时器")
            }
        }
        rw.Unlock()
        // 因为本帧数据不符合规则,所以也不用统计结果数组里的东西
    }
}
 
// 过滤规则先筛选出符合条件的目标数量
func filterRule(rule *protomsg.Rule, am *structure.AreaMap) structure.LittleRuleResult {
    if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" || rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a972" {
        // 处理的是人脸算法 如果这条规则配置的是人脸算法,过滤完条件之后直接得出结果,因为肯定没有数量条件,自己拼接
        //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" {
                if rule.RuleWithPre == "||" {
                    return structure.LittleRuleResult{}
                } else {
                    //logger.Debug("当前小规则是:",rule)
                    flag := "false"
                    // 把没有相似者的人脸从filterData中删除
                    for index := 0; index < len(am.FilterData); {
                        // 将达不到阈值的相似者从相似者数组中删除
                        logger.Info("看看相似者人数:",len(am.FilterData[index].Liker))
                        if len(am.FilterData[index].Liker) == 0 {
                            // Go 语言中切片删除元素的本质是:以被删除元素为分界点,将前后两个部分的内存重新连接起来。不用怀疑,数组删除元素就这么坑爹
                            am.FilterData = append(am.FilterData[:index], am.FilterData[index+1:]...)
                        } else {
                            index++
                        }
                    }
                    if len(am.FilterData) > 0 {
                        flag = "true"
                    }
                    logger.Info("---------人脸比对符合条件的数量为:",len(am.FilterData))
                    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + flag, rule.Sort}
                }
            }
            if rule.SdkId == "812b674b-2375-4589-919a-5c1c3278a97e" { // 人脸检测
                //logger.Debug("当前小规则是:",rule)
                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("-----------------------过规则之前区域内的人脸数量为:",am.TargetNum)
                        var args []*structure.Arg
                        if rule.RuleWithPre == "&&" {
                            args = am.FilterData
                            //logger.Info("过滤后的args的长度为:",len(args))
                        } else {
                            args = am.Args
                            //不清空之前的过滤数据,继续塞
                            //logger.Info("没过滤的args的长度为:",len(args))
                        }
                        // 先清空过滤后的数据,再往里塞本次过滤后的数据
                        am.FilterData = am.FilterData[0:0]
                        //logger.Info("-----------------------人脸过滤的args里的数量:", len(args))
                        for _, arg := range args {
                            var formula string
                            if rule.SdkArgAlias == "score" {
                                formula = strconv.FormatFloat(arg.Score, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
                                logger.Info("当前相似度小公式:", formula)
                            } else if rule.SdkArgAlias == "proportion" {
                                formula = strconv.FormatFloat(arg.Proportion, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
                                logger.Info("当前占比小公式:", formula)
                            } else {
                                formula = strconv.FormatFloat(arg.Size, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
                                logger.Info("当前尺寸小公式:", formula)
                            }
                            expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
                            result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
                            if result.(bool) {
                                am.FilterData = append(am.FilterData, arg) // 得到符合条件的过滤数据
                            }
                        }
                        am.TargetNum = len(am.FilterData) // 把符合条件的目标数量更新到targetNum字段
                        logger.Info("过完条件后的目标数量为:",am.TargetNum)
                        if am.TargetNum > 0 {
                            logger.Info("!!!!!!!!!人脸检测成功")
                            return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
                        } else {
                            return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
                        }
                    }
                } else if rule.SdkArgAlias == "" { // 什么参数都不配的情况
                    if am.TargetNum > 0 {
                        return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
                    } else {
                        return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
                    }
                }
            }
        }
    } else {
        // 处理的都是yolo数据
        if rule.PolygonId == am.AreaId { // 首先这条规则得是这个算法的规则,其次规则所对应的区域id要跟区域数据的id对的上
            if rule.SdkArgAlias == "score" || rule.SdkArgAlias == "proportion" || rule.SdkArgAlias == "size" { // 判断的是相似值,占比,尺寸等过滤条件,如果再有,还可以再加
                var args []*structure.Arg
                if rule.RuleWithPre == "&&" {
                    args = am.FilterData
                } else {
                    args = am.Args
                }
                // 先清空过滤后的数据,再往里塞本次过滤后的数据
                am.FilterData = am.FilterData[0:0]
                //logger.Debug("看看args:::::", args)
                for _, arg := range args {
                    var formula string
                    if rule.SdkArgAlias == "score" {
                        formula = strconv.FormatFloat(arg.Score, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
                        logger.Info("当前相似度小公式:", formula)
                    } else if rule.SdkArgAlias == "proportion" {
                        formula = strconv.FormatFloat(arg.Proportion, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
                        logger.Info("当前占比小公式:", formula)
                    } else {
                        formula = strconv.FormatFloat(arg.Size, 'f', -1, 64) + " " + rule.Operator + " " + rule.SdkArgValue // 得到字符串公式
                        logger.Info("当前尺寸小公式:", formula)
                    }
                    expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
                    result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
                    if result.(bool) {
                        am.FilterData = append(am.FilterData, arg) // 得到符合条件的过滤数据
                    }
                }
                am.TargetNum = len(am.FilterData) // 把符合条件的目标数量更新到targetNum字段
                if am.TargetNum > 0 {
                    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
                } else {
                    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
                }
 
            } else if rule.SdkArgAlias == "" {
                if am.TargetNum > 0 {
                    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "true", rule.Sort}
                } else {
                    return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + "false", rule.Sort}
                }
            }
        }
    }
    return structure.LittleRuleResult{}
}
 
// 如果有持续时间条件维护开启一个定时器
func duration(rule *protomsg.Rule, groupId string, am *structure.AreaMap, args *structure.SdkDatas, message *protomsg.SdkMessage) {
    if rule.PolygonId == am.AreaId { // 首先规则所对应的区域id要跟区域数据的id对的上  配置的算法要对的上
        if rule.SdkArgAlias == "duration" { //
            logger.Info("当前小规则是:---------", rule)
            // 先看看定时器元素队列中是否有这条规则的定时器,如果有就不能再次创建了
            rw.Lock()
            var flag bool = true
            for k, _ := range TimeEleList {
                if k == groupId+"+"+rule.Id {
                    flag = false // 有就置为false
                    logger.Info("有这个定时器,不再创建了:")
                }
            }
 
            if flag {
                timeLength, _ := strconv.Atoi(rule.SdkArgValue)
                timeEle := TimeElement{N: timeLength, InitN: timeLength, AlarmFlag: false, BufferFlag: 10, CacheSdkData: structure.ResultMsg{message, args.RuleResult}} // 扔进去一个定时器元素(并缓存当前画面帧数据)
                //TimeEleList = make(map[string]timeElement)
                TimeEleList[groupId+"+"+rule.Id] = &timeEle // 定时器元素以当前持续时间小规则id为键
                logger.Info("创建了计数器")
            }
            rw.Unlock()
        }
    }
}
 
// 给数据库的规则表达式代参 args: 一条子规则,区域数据
func transferParameters(rule *protomsg.Rule, am *structure.AreaMap) structure.LittleRuleResult {
    if rule.PolygonId == am.AreaId { // 首先规则所对应的区域id要跟区域数据的id对的上
        if rule.SdkArgAlias == "objCount" { // 如果参数是要区域内目标数量 即yolo 人脸不会有数量
            //logger.Info("当前小规则是:---------", rule)
            //logger.Info("得出结果阶段", "比较的规则是:", rule)
            if rule.Operator == "" {
                return structure.LittleRuleResult{am.SdkName, strconv.Itoa(am.TargetNum) + "" + rule.RuleWithPre, rule.Sort} // 如果后面不跟操作符就直接返回数量  比如要跟下一个区域比较数量的就直接返回本区域的数量
            }
            //args := am.targetNum     targetNum 已成所有目标的总数量,这里只算yolo的
            var num int = 0
            for _, data := range am.FilterData {
                if data.IsYolo {
                    num++
                }
            }
            formula := strconv.Itoa(num) + " " + rule.Operator + " " + rule.SdkArgValue
            expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
            result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
            return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + " " + strconv.FormatBool(result.(bool)), rule.Sort}
            // 加上关于算法的判断条件,不能只有关于规则的,有的算法本身就是一个规则,如个体静止,靠右行,所以,拿到当前子规则的sdkid来判断是否是那些特殊的规则
        }
    }
    return structure.LittleRuleResult{}
}
func timeRuleResult(rule *protomsg.Rule, am *structure.AreaMap) structure.LittleRuleResult {
    if rule.PolygonId == am.AreaId { // 首先规则所对应的区域id要跟区域数据的id对的上
        if rule.SdkArgAlias == "time_rule" { // 判断是否符合时间规
            //logger.Info("----------当前时间规则:---------", rule)
            // 根据放值字段里存的时间规则的id去另一个表里查需要比对的时间段(比如当前时间是周三,应根据区域id查出其周三的几个布防时间段,数组)
            //logger.Info("时间规则的测试")
            now := time.Now()
            index := getIndexOfWeek(now.Weekday().String())
            timeList := GetTimeById(rule.SdkArgValue, index)
            //logger.Info("当天的时间段集合:----------", timeList)
            //logger.Info("从数据库中查出的时间规则:", timeList)
            // 判断图片数据的时间是否符合当前规则 在一个即为true,全不在为false
 
            if rule.Operator == "satisfy" || rule.Operator == "==" { // 满足所选的时间规则
                flag := "false"
                for _, timeSlot := range timeList {
                    formula := "'" + timeSlot.Start + "'" + "<" + "'" + am.Time + "'"
                    expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
                    result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
 
                    formula1 := "'" + timeSlot.End + "'" + ">" + "'" + am.Time + "'"
                    expression1, _ := govaluate.NewEvaluableExpression(formula1) // 得到数学公式
                    result1, _ := expression1.Evaluate(nil)                      // 得到数学公式的结果
                    //logger.Info("看看这两尊大神", result, result1)
                    if result.(bool) && result1.(bool) {
                        flag = "true"
                        break
                    }
                }
                return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + flag, rule.Sort}
            }
 
            if rule.Operator == "unsatisfy" || rule.Operator == "!=" { // 不满足所选的时间规则
                flag := "true"
                for _, timeSlot := range timeList {
                    formula := "'" + timeSlot.Start + "'" + " < " + "'" + am.Time + "'"
                    //logger.Info("-----------------时间规则不满足的公式start:", formula)
                    expression, _ := govaluate.NewEvaluableExpression(formula) // 得到数学公式
                    result, _ := expression.Evaluate(nil)                      // 得到数学公式的结果
 
                    formula1 := "'" + timeSlot.End + "'" + " > " + "'" + am.Time + "'"
                    //logger.Info("-----------------时间规则不满足的公式end:", formula1)
                    expression1, _ := govaluate.NewEvaluableExpression(formula1) // 得到数学公式
                    result1, _ := expression1.Evaluate(nil)                      // 得到数学公式的结果
                    if result.(bool) && result1.(bool) {
                        flag = "false"
                        break
                    }
                }
                return structure.LittleRuleResult{am.SdkName, rule.RuleWithPre + "" + flag, rule.Sort}
            }
 
        }
    }
    return structure.LittleRuleResult{}
}