package simulation import ( "net" "strings" "fmt" "net/http" "strconv" "sync" "go.uber.org/zap" "joylink.club/bj-rtsts-server/ats/verify/protos/state" "joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/dynamics" "joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory" "joylink.club/bj-rtsts-server/dto" ) var simulationId_prefix = (func() string { ip := "127.0.0.1" addrList, err := net.InterfaceAddrs() if err != nil { panic(err) } for _, address := range addrList { if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() { if ipNet.IP.To4() != nil { ip = ipNet.IP.String() } } } ipArr := strings.Split(ip, ".") return ipArr[2] + "_" + ipArr[3] })() func init() { dynamics.RegisterTrainInfoHandler(func(info *dynamics.TrainInfo) { for _, simulation := range GetSimulationArr() { sta, ok := simulation.Memory.Status.TrainStateMap.Load(strconv.Itoa(int(info.Number))) if ok { memory.UpdateTrainState(simulation, convert(info, sta.(*state.TrainState), memory.QueryMapVerifyStructure(simulation.MapId))) break } } }) } // 仿真存储集合 var simulationMap sync.Map // 创建仿真对象 func CreateSimulation(mapId int32) string { simulationId := createSimulationId(mapId) _, e := simulationMap.Load(simulationId) if !e { verifySimulation := memory.CreateSimulation(mapId, simulationId) //通知动力学 httpCode, _, err := dynamics.SendSimulationStartReq(buildLineBaseInfo(memory.QueryMapVerifyStructure(verifySimulation.MapId))) if httpCode != http.StatusOK || err != nil { panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)}) } simulationMap.Store(simulationId, verifySimulation) dynamicsRun(verifySimulation) } return simulationId } // 删除仿真对象 func DestroySimulation(simulationId string) { //移除道岔状态发送 dynamics.Stop() //通知动力学 httpCode, _, err := dynamics.SendSimulationEndReq() if httpCode != http.StatusOK || err != nil { panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)}) } simulationMap.Delete(simulationId) } // 创建时生成仿真Id func createSimulationId(mapId int32) string { // 当前服务器IP + 端口 + 地图 return simulationId_prefix + "_" + strconv.Itoa(config.Config.Server.Port) + "_" + strconv.Itoa(int(mapId)) } // 获取仿真列表 func ListAllSimulations() []*dto.SimulationInfoRepDto { simArr := []*dto.SimulationInfoRepDto{} simulationMap.Range(func(k, v any) bool { s := v.(*memory.VerifySimulation) simArr = append(simArr, &dto.SimulationInfoRepDto{ SimulationId: s.SimulationId, MapId: strconv.Itoa(int(s.MapId)), }) return true }) return simArr } // 根据仿真id查找仿真实例 func FindSimulation(simulationId string) *memory.VerifySimulation { m, e := simulationMap.Load(simulationId) if e { return m.(*memory.VerifySimulation) } return nil } // 获取普通仿真数组 func GetSimulationArr() []*memory.VerifySimulation { result := []*memory.VerifySimulation{} simulationMap.Range(func(k, v any) bool { result = append(result, v.(*memory.VerifySimulation)) return true }) return result } func convert(info *dynamics.TrainInfo, sta *state.TrainState, vs *memory.VerifyStructure) *state.TrainState { zap.S().Debugf("原始消息:[%d-%d-%d]", info.Number, info.Link, info.LinkOffset) sta.HeadLinkId = strconv.Itoa(int(info.Link)) sta.HeadLinkOffset = int64(info.LinkOffset) sta.Up = info.Up id, port, offset, runDirection, pointTo := memory.QueryDeviceByCalcLink(vs, int32(info.Link), sta.HeadLinkOffset, sta.Up, sta.RunDirection) zap.S().Debugf("转换后的消息:[%d-车头:%s-偏移:%d-上行:%v-是否ab:%v]", info.Number, id, offset, runDirection, pointTo) sta.HeadDeviceId = id sta.DevicePort = port sta.HeadOffset = offset sta.PointTo = pointTo sta.RunDirection = runDirection /* modeller := vs.LinkModelMap[int32(info.Link)] model := modeller.(*device.LinkModel) for i, dp := range model.DevicePositions { if uint32(dp.Offset) >= info.LinkOffset { var minLinkRef *graphicData.RelatedRef var minOffset int32 var maxOffset int32 if i == 0 { minLinkRef = model.SectionLinkMap[dp.Device.GetGraphicId()] minOffset = dp.Offset maxOffset = model.DevicePositions[i+1].Offset } else { minLinkRef = model.SectionLinkMap[model.DevicePositions[i-1].Device.GetGraphicId()] minOffset = model.DevicePositions[i-1].Offset maxOffset = dp.Offset } switch minLinkRef.DevicePort { case 0: sta.HeadLinkId = minLinkRef.GetId() sta.HeadLinkOffset = int64(info.LinkOffset - uint32(minOffset)) case 1: sta.HeadLinkId = minLinkRef.GetId() sta.HeadLinkOffset = int64(uint32(maxOffset) - info.LinkOffset) } break } } zap.S().Debugf("转换后的消息:[%d-%s-%d]", info.Number, sta.HeadLinkId, sta.HeadLinkOffset) */ sta.Slope = int32(info.Slope) sta.Upslope = info.UpSlope sta.RunningUp = info.Up sta.RunningResistanceSum = float32(info.TotalResistance) / 1000 sta.AirResistance = float32(info.AirResistance) / 1000 sta.RampResistance = float32(info.SlopeResistance) / 1000 sta.CurveResistance = float32(info.CurveResistance) / 1000 sta.Speed = info.Speed * 3.6 sta.HeadSensorSpeed1 = info.HeadSpeed1 * 3.6 sta.HeadSensorSpeed2 = info.HeadSpeed2 * 3.6 sta.TailSensorSpeed1 = info.TailSpeed1 * 3.6 sta.TailSensorSpeed2 = info.TailSpeed2 * 3.6 sta.HeadRadarSpeed = info.HeadRadarSpeed * 3.6 sta.TailRadarSpeed = info.TailRadarSpeed * 3.6 return sta } func dynamicsRun(verifySimulation *memory.VerifySimulation) { _ = dynamics.Run(func() []*dynamics.TurnoutInfo { stateSlice := memory.GetAllTurnoutState(verifySimulation) var turnoutInfoSlice []*dynamics.TurnoutInfo for _, sta := range stateSlice { code64, err := strconv.ParseUint(sta.Id, 10, 16) if err != nil { zap.S().Error("id转uint16报错", err) } info := dynamics.TurnoutInfo{ Code: uint16(code64), NPosition: sta.Normal, RPosition: sta.Reverse, } turnoutInfoSlice = append(turnoutInfoSlice, &info) } return turnoutInfoSlice }) } func buildLineBaseInfo(vs *memory.VerifyStructure) *dynamics.LineBaseInfo { var links []*dynamics.Link var slopes []*dynamics.Slope var curves []*dynamics.Curve for _, link := range vs.LinkModelMap { id, _ := strconv.Atoi(link.Index) var aTurnoutId int if link.ARelatedSwitchRef.SwitchDevice != nil { aTurnoutId, _ = strconv.Atoi(link.ARelatedSwitchRef.SwitchDevice.GetIndex()) } var bTurnoutId int if link.BRelatedSwitchRef.SwitchDevice != nil { bTurnoutId, _ = strconv.Atoi(link.BRelatedSwitchRef.SwitchDevice.GetIndex()) } links = append(links, &dynamics.Link{ ID: int32(id), Len: link.Length, ARelTurnoutId: int32(aTurnoutId), ARelTurnoutPoint: link.ARelatedSwitchRef.Port.Name(), BRelTurnoutId: int32(bTurnoutId), BRelTurnoutPoint: link.BRelatedSwitchRef.Port.Name(), }) } for _, slope := range vs.SlopeModelMap { id, _ := strconv.Atoi(slope.Index) slopes = append(slopes, &dynamics.Slope{ ID: int32(id), StartLinkId: slope.StartLinkIndex, StartLinkOffset: slope.StartLinkOffset, EndLinkId: slope.EndLinkIndex, EndLinkOffset: slope.EndLinkOffset, DegreeTrig: slope.DegreeTrig, }) } for _, curve := range vs.CurveModelMap { id, _ := strconv.Atoi(curve.Index) curves = append(curves, &dynamics.Curve{ ID: int32(id), StartLinkId: curve.StartLinkIndex, StartLinkOffset: curve.StartLinkOffset, EndLinkId: curve.EndLinkIndex, EndLinkOffset: curve.EndLinkOffset, Curvature: curve.Curvature, }) } return &dynamics.LineBaseInfo{ LinkList: links, SlopeList: slopes, CurveList: curves, } }