package service import ( "basic.com/pubsub/protomsg.git" "basic.com/valib/bhomeclient.git" "basic.com/valib/bhomedbapi.git" "basic.com/valib/logger.git" "encoding/json" "github.com/satori/go.uuid" "strings" "vamicro/scene-service/models" "vamicro/scene-service/vo" ) type CameraPolygonService struct { bk bhomeclient.Broker } func NewCameraPolygonService(broker bhomeclient.Broker) *CameraPolygonService { return &CameraPolygonService{ bk: broker, } } func (sv CameraPolygonService) Save(cPolygon vo.CameraPolygonVo) ([]string, []string) { var model models.CameraPolygon var delS []string var delF []string setPolygons, _ := model.FindAllByCameraId(cPolygon.CameraId) //已经配置的多边形,判断删除的是否有正在使用 logger.Debug("setPolygons:", setPolygons) if setPolygons != nil { delS, delF = getDeletedPolygons(setPolygons, cPolygon) } doResult := false var chIdArr []string for _, line := range cPolygon.Line { if line.Name != models.CAMERAPOLYGON_AREA_ALL { chIdArr = append(chIdArr, line.Id) model.Id = line.Id model.Name = line.Name model.CameraId = cPolygon.CameraId lineBytes, err := json.Marshal(line.Location) if err != nil { continue } model.Polygon = string(lineBytes) model.Type = models.TYPE_LINE if savePolygon(model) { if !doResult { doResult = true } } } } for _, rect := range cPolygon.Rect { if rect.Name != models.CAMERAPOLYGON_AREA_ALL { chIdArr = append(chIdArr, rect.Id) rectBytes, _ := json.Marshal(rect.Location) model = models.CameraPolygon{ Id: rect.Id, Name: rect.Name, Polygon: string(rectBytes), CameraId: cPolygon.CameraId, } //判断矩形内是否有箭头 arrows := GetArrowInPolygon(cPolygon.Arrow, rect.Location) //多边形内部的箭头 if len(arrows) > 0 { arrowBytes, _ := json.Marshal(arrows[0]) //取第一个箭头 model.DirectionLine = string(arrowBytes) } model.Type = models.TYPE_RECT if savePolygon(model) { if !doResult { doResult = true } } } } for _, pg := range cPolygon.Polygon { if pg.Name != models.CAMERAPOLYGON_AREA_ALL { chIdArr = append(chIdArr, pg.Id) pgbytes, _ := json.Marshal(pg.Location) model = models.CameraPolygon{ Id: pg.Id, Name: pg.Name, Polygon: string(pgbytes), CameraId: cPolygon.CameraId, } arrows := GetArrowInPolygon(cPolygon.Arrow, pg.Location) //多边形内部的箭头 if len(arrows) > 0 { arrowBytes, _ := json.Marshal(arrows[0]) //多边形内只能有一个箭头 model.DirectionLine = string(arrowBytes) } model.Type = models.TYPE_POLYGON if savePolygon(model) { if !doResult { doResult = true } } } } sv.addDbChangeMsg(chIdArr, protomsg.DbAction_Update) return delS, delF } func savePolygon(model models.CameraPolygon) bool { _, flag := model.SelectById(model.Id) if flag { //存在则更新 existModel, exist := model.Exist(model.CameraId, model.Name) if !exist || (exist && existModel.Id == model.Id) { model.DefenceState = existModel.DefenceState if updateResult, _ := model.Update(); updateResult { return true } } } else { //新增 _, exist := model.Exist(model.CameraId, model.Name) if exist { return false } model.Id = uuid.NewV4().String() model.DefenceState = 1 //新增时区域的布撤防状态默认开启 if saveResult, _ := model.Insert(); saveResult { return true } } return false } func min(num1 float64, num2 float64) float64 { if num1 < num2 { return num1 } return num2 } func max(num1 float64, num2 float64) float64 { if num1 < num2 { return num2 } return num1 } //取出多边形内部的箭头 func GetArrowInPolygon(arrows []vo.PolygonS, polygon []vo.Point) (arr []vo.PolygonS) { for _, line := range arrows { arrow := line.Location lenth := len(arrow) m := 0 for _, point := range arrow { if pintIsInPolygon(point, polygon) { m++ } else { break } } if m == lenth { arr = append(arr, line) } } return arr } //PintIsInPolygon 判断点是否在多边形内部 //point为要判断的坐标点 //polygon是多边形各点数组 func pintIsInPolygon(point vo.Point, polygon []vo.Point) bool { var nCross int = 0 for i := 0; i < len(polygon); i++ { p1 := polygon[i] p2 := polygon[(i+1)%len(polygon)] if p1.Y == p2.Y { continue } if point.Y < float64(min(p1.Y, p2.Y)) { continue } if point.Y > float64(max(p1.Y, p2.Y)) { continue } X := (point.Y-float64(p1.Y))*float64((p2.X-p1.X))/float64((p2.Y-p1.Y)) + float64(p1.X) if X > point.X { nCross++ } } return nCross%2 != 0 } //返回删除成功的多边形名称数组以及删除失败的多边形名称数组 func getDeletedPolygons(setPolygons []models.CameraPolygon, savePolygon vo.CameraPolygonVo) (delS []string, delF []string) { idMap := make(map[string]string, 0) if savePolygon.Line != nil { for _, line := range savePolygon.Line { idMap[line.Id] = line.Id } } if savePolygon.Rect != nil { for _, rect := range savePolygon.Rect { idMap[rect.Id] = rect.Id } } if savePolygon.Polygon != nil { for _, polygon := range savePolygon.Polygon { idMap[polygon.Id] = polygon.Id } } var polygonId string var polygonName string for _, model := range setPolygons { polygonId = model.Id polygonName = model.Name if _, ok := idMap[polygonId]; !ok { //多边形已被删除 if polygonName != models.CAMERAPOLYGON_AREA_ALL { if model.Delete(polygonId, polygonName, savePolygon.Force) { //将删除掉的区域在规则组中的名称替换为空NULL delS = append(delS, polygonName) //删除成功 } else { delF = append(delF, polygonName) //删除失败 } } } } return delS, delF } func (sv CameraPolygonService) FindByCameraId(cameraId string) vo.CameraPolygonVo { var voInfo = vo.CameraPolygonVo{ CameraId: cameraId, } if models.IsStack(cameraId) { var sckApi bhomedbapi.FileStackApi b, fileS := sckApi.Show(cameraId) if b { voInfo.SnapshotUrl = "" voInfo.CameraName = fileS.Name } } else { //可能是本地摄像机 var localCamApi bhomedbapi.CameraApi localCam, err := localCamApi.GetCameraById(cameraId) if err == nil && localCam.SnapshotUrl != "" { voInfo.SnapshotUrl = localCam.SnapshotUrl voInfo.CameraName = localCam.Name } else { //也可能是国标摄像机 var gbCamApi bhomedbapi.Gb28181Api gbCamera, err := gbCamApi.GetCameraById(cameraId) if err == nil && gbCamera.SnapshotUrl != "" { voInfo.SnapshotUrl = gbCamera.SnapshotUrl voInfo.CameraName = localCam.Name } } } var cPolygon models.CameraPolygon polygons, _ := cPolygon.FindAllByCameraId(cameraId) lines := make([]vo.PolygonS, 0) rects := make([]vo.PolygonS, 0) pgs := make([]vo.PolygonS, 0) //每个摄像机都有个默认的区域,叫全部区域 pgs = append(pgs, vo.PolygonS{ Id: cameraId, Name: models.CAMERAPOLYGON_AREA_ALL, Location: []vo.Point{}, DefenceState: 1, }) directionLines := make([]vo.PolygonS, 0) if polygons != nil { for _, p := range polygons { location := make([]vo.Point, 0) var dline vo.PolygonS if p.DirectionLine != "" { if err := json.Unmarshal([]byte(p.DirectionLine), &dline); err == nil { //存在一个箭头在多个面内的情况 existLine := false for _, el := range directionLines { if el.Id == dline.Id { existLine = true break } } if !existLine { directionLines = append(directionLines, dline) } } } if p.Polygon != "" { if err := json.Unmarshal([]byte(p.Polygon), &location); err == nil { if p.Type == models.TYPE_LINE { //线 lines = append(lines, vo.PolygonS{ Id: p.Id, Name: p.Name, Location: location, DefenceState: p.DefenceState, }) } if p.Type == models.TYPE_RECT { rects = append(rects, vo.PolygonS{ Id: p.Id, Name: p.Name, Location: location, DefenceState: p.DefenceState, }) } if p.Type == models.TYPE_POLYGON { pgs = append(pgs, vo.PolygonS{ Id: p.Id, Name: p.Name, Location: location, DefenceState: p.DefenceState, }) } } } } } voInfo.Arrow = directionLines voInfo.Line = lines voInfo.Rect = rects voInfo.Polygon = pgs return voInfo } func (sv CameraPolygonService) addDbChangeMsg(chIdArr []string, action protomsg.DbAction) { dbMsg := protomsg.DbChangeMessage{ Table: protomsg.TableChanged_T_CameraPolygon, Id: strings.Join(chIdArr, ","), Action: action, Info: string(""), } bts, _ := json.Marshal(&dbMsg) sv.bk.Publish(ProcName, bts) } func (sv CameraPolygonService) addPgnRelationMsg(action protomsg.DbAction) { dbMsg := protomsg.DbChangeMessage{ Table: protomsg.TableChanged_T_CameraPolygonRelation, Id: "", Action: action, Info: string(""), } bts, _ := json.Marshal(&dbMsg) sv.bk.Publish(ProcName, bts) } // 获取同步摄像机场景的数据 func (sv CameraPolygonService) GetSyncSceneData() vo.SyncPolygonResult { res := vo.SyncPolygonResult{} cameraGroupM := models.CameraGroup{} cameraPolyginM := models.CameraPolygon{} cameraPolygonRelationM := models.CameraPolygonRelation{} cameraRuleGroupM := models.CameraRuleGroup{} cameraRuleGroupArgM := models.CameraRuleGroupArg{} cameraTaskLinkM := models.CameraTaskLink{} cameraTimeruleM := models.CameraTimerule{} res.CameraPolygon = cameraPolyginM.FindAll() res.CameraGroup = cameraGroupM.FindAll() res.CameraPolygonRelation = cameraPolygonRelationM.FindAll() res.CameraRuleGroup = cameraRuleGroupM.FindAll() res.CameraRuleGroupArg = cameraRuleGroupArgM.FindAll() res.CameraTaskLink, _ = cameraTaskLinkM.FindAll() res.CameraTimerule, _ = cameraTimeruleM.FindAll() return res } func (sv CameraPolygonService) DeleteByIds(ids []string) bool { var cp models.CameraPolygon if !cp.DeleteByIds(ids) { return false } sv.addDbChangeMsg(ids, protomsg.DbAction_Delete) return true }