This commit is contained in:
walker 2023-08-18 10:22:23 +08:00
commit 897c5b9085
33 changed files with 1980 additions and 839 deletions

View File

@ -204,9 +204,10 @@ func addTrain(c *gin.Context) {
id := strconv.Itoa(i)
rsp := &state.TrainState{
Id: id,
HeadLinkId: req.HeadLinkId,
HeadLinkOffset: req.HeadLinkOffset,
Up: req.Up,
HeadDeviceId: req.Id,
HeadOffset: req.HeadOffset,
DevicePort: req.DevicePort,
RunDirection: req.RunDirection,
}
memory.AddTrainState(simulation, rsp)
c.JSON(http.StatusOK, &rsp)

File diff suppressed because it is too large Load Diff

View File

@ -473,6 +473,16 @@ type TrainState struct {
TrainLength int64 `protobuf:"varint,23,opt,name=trainLength,proto3" json:"trainLength,omitempty"`
// 列车是否显示
Show bool `protobuf:"varint,24,opt,name=show,proto3" json:"show,omitempty"`
// 列车车头所在设备ID
HeadDeviceId string `protobuf:"bytes,25,opt,name=headDeviceId,proto3" json:"headDeviceId,omitempty"`
// 列车车头所在设备偏移量
HeadOffset int64 `protobuf:"varint,26,opt,name=headOffset,proto3" json:"headOffset,omitempty"`
// 设备端口
DevicePort string `protobuf:"bytes,27,opt,name=devicePort,proto3" json:"devicePort,omitempty"`
// 运行方向指向(区段A-B,道岔:-> 岔心)
PointTo bool `protobuf:"varint,28,opt,name=pointTo,proto3" json:"pointTo,omitempty"`
// 运行上下行(公里标 上行:小 -> 大,下行:大 -> 小)
RunDirection bool `protobuf:"varint,29,opt,name=runDirection,proto3" json:"runDirection,omitempty"`
}
func (x *TrainState) Reset() {
@ -675,6 +685,41 @@ func (x *TrainState) GetShow() bool {
return false
}
func (x *TrainState) GetHeadDeviceId() string {
if x != nil {
return x.HeadDeviceId
}
return ""
}
func (x *TrainState) GetHeadOffset() int64 {
if x != nil {
return x.HeadOffset
}
return 0
}
func (x *TrainState) GetDevicePort() string {
if x != nil {
return x.DevicePort
}
return ""
}
func (x *TrainState) GetPointTo() bool {
if x != nil {
return x.PointTo
}
return false
}
func (x *TrainState) GetRunDirection() bool {
if x != nil {
return x.RunDirection
}
return false
}
// 仿真运行时状态变化量,当前时刻与上一时刻比较得到
type VariationStatus struct {
state protoimpl.MessageState
@ -911,7 +956,7 @@ var file_device_state_proto_rawDesc = []byte{
0x72, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xce, 0x06, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x69,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xf0, 0x07, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x69,
0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01,
0x28, 0x08, 0x52, 0x02, 0x75, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x65, 0x61, 0x64, 0x4c, 0x69,
@ -964,52 +1009,62 @@ var file_device_state_proto_rawDesc = []byte{
0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x18, 0x17, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x4c, 0x65,
0x6e, 0x67, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x18, 0x20, 0x01,
0x28, 0x08, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x22, 0xe7, 0x01, 0x0a, 0x0f, 0x56, 0x61, 0x72,
0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x0c,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x6e,
0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x54, 0x72,
0x61, 0x69, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x54, 0x72,
0x61, 0x69, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6d,
0x6f, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x0d, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x77, 0x69, 0x74, 0x63,
0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x53,
0x77, 0x69, 0x74, 0x63, 0x68, 0x12, 0x3b, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e,
0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
0x74, 0x65, 0x52, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x22, 0xb4, 0x01, 0x0a, 0x10, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x31, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x69, 0x6e,
0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x74,
0x61, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0a,
0x74, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x73, 0x77,
0x69, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x12, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x53, 0x74,
0x61, 0x74, 0x65, 0x52, 0x0b, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65,
0x12, 0x37, 0x0a, 0x0c, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x73, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x13, 0x50, 0x75,
0x73, 0x68, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03,
0x61, 0x6c, 0x6c, 0x12, 0x34, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x56,
0x61, 0x72, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09,
0x76, 0x61, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x61, 0x6c, 0x6c,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73,
0x74, 0x61, 0x74, 0x65, 0x2e, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x2a, 0x37, 0x0a, 0x0b, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12,
0x07, 0x0a, 0x03, 0x41, 0x6e, 0x79, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x78, 0x6c, 0x65,
0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x10, 0x02, 0x12, 0x0a, 0x0a,
0x06, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x10, 0x03, 0x42, 0x54, 0x0a, 0x25, 0x63, 0x6c, 0x75,
0x62, 0x2e, 0x6a, 0x6f, 0x79, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6a, 0x72, 0x74, 0x73, 0x73,
0x2e, 0x61, 0x74, 0x73, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x73, 0x42, 0x10, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x19, 0x2e, 0x2f, 0x61, 0x74, 0x73, 0x2f, 0x76, 0x65, 0x72, 0x69,
0x66, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x28, 0x08, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x64,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
0x68, 0x65, 0x61, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a,
0x68, 0x65, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0a, 0x68, 0x65, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x6f, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70,
0x6f, 0x69, 0x6e, 0x74, 0x54, 0x6f, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x44, 0x69, 0x72,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x75,
0x6e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xe7, 0x01, 0x0a, 0x0f, 0x56,
0x61, 0x72, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35,
0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x61,
0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x54, 0x72, 0x61, 0x69, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
0x54, 0x72, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72,
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x38, 0x0a,
0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x18, 0x03,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x77, 0x69,
0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x64, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x12, 0x3b, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x64, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x13, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x74, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb4, 0x01, 0x0a, 0x10, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x31, 0x0a, 0x0a, 0x74, 0x72, 0x61,
0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e,
0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
0x52, 0x0a, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x0b,
0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x12, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68,
0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61,
0x74, 0x65, 0x12, 0x37, 0x0a, 0x0c, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65,
0x2e, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x73,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x13,
0x50, 0x75, 0x73, 0x68, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x34, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65,
0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x52, 0x09, 0x76, 0x61, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x61,
0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x2a, 0x37, 0x0a, 0x0b, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70,
0x65, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x6e, 0x79, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x78,
0x6c, 0x65, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x10, 0x02, 0x12,
0x0a, 0x0a, 0x06, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x10, 0x03, 0x42, 0x54, 0x0a, 0x25, 0x63,
0x6c, 0x75, 0x62, 0x2e, 0x6a, 0x6f, 0x79, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6a, 0x72, 0x74,
0x73, 0x73, 0x2e, 0x61, 0x74, 0x73, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x42, 0x10, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74,
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x19, 0x2e, 0x2f, 0x61, 0x74, 0x73, 0x2f, 0x76, 0x65,
0x72, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x74, 0x61, 0x74,
0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -5,13 +5,14 @@ import (
"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"
"net/http"
"strconv"
"sync"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/dto"
@ -39,7 +40,7 @@ func init() {
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.UpdateTrainState(simulation, convert(info, sta.(*state.TrainState), memory.QueryMapVerifyStructure(simulation.MapId)))
break
}
}
@ -54,15 +55,14 @@ func CreateSimulation(mapId int32) string {
simulationId := createSimulationId(mapId)
_, e := simulationMap.Load(simulationId)
if !e {
////通知动力学
//httpCode, _, err := dynamics.SendSimulationStartReq()
//if httpCode != http.StatusOK || err != nil {
// panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
//}
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)
//道岔状态发送
startSendTurnoutInfo(simulationId, verifySimulation)
dynamicsRun(verifySimulation)
}
return simulationId
}
@ -70,7 +70,7 @@ func CreateSimulation(mapId int32) string {
// 删除仿真对象
func DestroySimulation(simulationId string) {
//移除道岔状态发送
dynamics.RemoveTurnoutInfoSource(simulationId)
dynamics.Stop()
//通知动力学
httpCode, _, err := dynamics.SendSimulationEndReq()
if httpCode != http.StatusOK || err != nil {
@ -118,9 +118,47 @@ func GetSimulationArr() []*memory.VerifySimulation {
return result
}
func convert(info *dynamics.TrainInfo, sta state.TrainState) *state.TrainState {
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 * 10)
sta.HeadLinkOffset = int64(info.LinkOffset)
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
@ -135,11 +173,11 @@ func convert(info *dynamics.TrainInfo, sta state.TrainState) *state.TrainState {
sta.TailSensorSpeed2 = info.TailSpeed2 * 3.6
sta.HeadRadarSpeed = info.HeadRadarSpeed * 3.6
sta.TailRadarSpeed = info.TailRadarSpeed * 3.6
return &sta
return sta
}
func startSendTurnoutInfo(simulationId string, verifySimulation *memory.VerifySimulation) {
dynamics.AddTurnoutInfoSource(simulationId, func() []*dynamics.TurnoutInfo {
func dynamicsRun(verifySimulation *memory.VerifySimulation) {
_ = dynamics.Run(func() []*dynamics.TurnoutInfo {
stateSlice := memory.GetAllTurnoutState(verifySimulation)
var turnoutInfoSlice []*dynamics.TurnoutInfo
for _, sta := range stateSlice {
@ -157,3 +195,55 @@ func startSendTurnoutInfo(simulationId string, verifySimulation *memory.VerifySi
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,
}
}

View File

@ -1,6 +1,9 @@
package face
import "strings"
import (
"fmt"
"strings"
)
// 设备模型基类
type DeviceModel struct {
@ -30,9 +33,35 @@ func (dm *DeviceModel) GetIndex() string {
// 设备端口枚举定义
type PortEnum int8
func (pe PortEnum) Name() string {
switch pe {
case A:
return "A"
case B:
return "B"
case C:
return "C"
default:
panic(fmt.Sprintf("未知的PortEnum%d", pe))
}
}
// 设备端口枚举值
const (
A PortEnum = iota
B
C
)
func GetPortEnum(i int8) PortEnum {
switch i {
case int8(A):
return A
case int8(B):
return B
case int8(C):
return C
default:
panic(fmt.Sprintf("未知的PortEnum%d", i))
}
}

View File

@ -2,7 +2,6 @@ package memory
import (
"container/list"
"fmt"
"math"
"reflect"
"sort"
@ -13,6 +12,8 @@ import (
"joylink.club/bj-rtsts-server/dto"
)
// 参与计算的坡度与曲度均为正线公里标,如果有其他坐标系需要转换
// 参与计算结构体信息
type buildCalcStruct struct {
AxlePointMap map[string]*graphicData.AxleCounting
@ -23,17 +24,23 @@ type buildCalcStruct struct {
// 参与计算link时的区段结构体
type buildCalcSectionStruct struct {
Data *graphicData.Section
APoint *graphicData.AxleCounting // a点计轴
BPoint *graphicData.AxleCounting // b点计轴
axlePoints map[graphicData.RelatedRef_DevicePort]*graphicData.AxleCounting // 关联计轴map
stopPositions []*graphicData.StopPosition // 停车位
transponders []*graphicData.Transponder // 应答器
signals []*graphicData.Signal // 信号机
slopes map[string]*graphicData.KilometerSystem // 坡度公里标
curvatures map[string]*graphicData.KilometerSystem // 曲度公里标
}
// 参与计算的
type buildCalcTurnoutStruct struct {
Data *graphicData.Turnout
APoint *graphicData.AxleCounting //a点计轴
BPoint *graphicData.AxleCounting //b点计轴
CPoint *graphicData.AxleCounting //c点计轴
axlePoints map[graphicData.RelatedRef_DevicePort]*graphicData.AxleCounting // 关联计轴map
CrossKilometerSystem *graphicData.KilometerSystem // 道岔岔心位置
transponders map[graphicData.RelatedRef_DevicePort][]*graphicData.Transponder // 应答器
signals map[graphicData.RelatedRef_DevicePort]*graphicData.Signal // 对应位置信号机
slopes map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem // 坡度公里标
curvatures map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem // 曲度公里标
}
// 根据地图信息生成calcLink数据
@ -48,6 +55,7 @@ func BuildCalculateLinkData(gd *graphicData.RtssGraphicStorage) []*graphicData.C
Common: &graphicData.CommonInfo{},
Index: int32(id),
Points: []*graphicData.Point{},
Length: 0,
DevicePositions: []*graphicData.CalculateLink_DevicePosition{},
}
allTurnout := true
@ -60,20 +68,14 @@ func BuildCalculateLinkData(gd *graphicData.RtssGraphicStorage) []*graphicData.C
// 计算长度
item.Length = item.Length + calcGraphicLenBySection(section)
// 放入设备偏移
offset, prevKm = getGraphicSectionRefDevices(devicePosistionMap, section, offset, prevKm)
// 区段时A点取小端B点取大端没有的话赋值 refVal
if index == 0 {
item.ARelatedRef = getGraphicSectionPointRef(section, true, refVal)
} else {
item.BRelatedRef = getGraphicSectionPointRef(section, false, refVal)
}
offset, prevKm = getGraphicSectionRefDevices(refVal, devicePosistionMap, section, offset, prevKm)
} else {
allTurnout = allTurnout && true
turnout := gm.TurnoutMap[refVal.Id]
// 计算长度
item.Length = item.Length + calcGraphicLenByTurnout(turnout, refVal.DevicePort)
// 放入设备偏移
offset, prevKm = getGraphicTurnoutRefDevices(devicePosistionMap, turnout, offset, prevKm)
offset, prevKm = getGraphicTurnoutRefDevices(refVal, devicePosistionMap, turnout, offset, prevKm)
// 道岔时左右端直接赋值
if index == 0 {
item.ARelatedRef = refVal
@ -85,11 +87,14 @@ func BuildCalculateLinkData(gd *graphicData.RtssGraphicStorage) []*graphicData.C
for _, v := range devicePosistionMap {
item.DevicePositions = append(item.DevicePositions, v)
}
sort.SliceStable(item.DevicePositions, func(i, j int) bool {
return item.DevicePositions[i].Offset < item.DevicePositions[j].Offset
})
// 如果全部为道岔,则长度使用岔心减岔心
if allTurnout {
tk1 := gm.TurnoutMap[pathArr[0].Id].CrossKilometerSystem.Kilometer
tk2 := gm.TurnoutMap[pathArr[len(pathArr)-1].Id].CrossKilometerSystem.Kilometer
item.Length = int32(tk2 - tk1)
item.Length = int32(math.Abs(float64(tk2 - tk1)))
}
resultArr = append(resultArr, item)
}
@ -98,97 +103,196 @@ func BuildCalculateLinkData(gd *graphicData.RtssGraphicStorage) []*graphicData.C
// 计算区段长度
func calcGraphicLenBySection(section *buildCalcSectionStruct) int32 {
if section.APoint == nil || section.BPoint == nil {
if len(section.axlePoints) != 2 {
zap.S().Warnf("区段【%s】端点位置缺失\n", section.Data.Common.Id)
return 0
}
start := section.BPoint.KilometerSystem.Kilometer
end := section.APoint.KilometerSystem.Kilometer
if end > start {
return int32(end - start)
} else {
return int32(start - end)
var length int64 // 两端公里标相减即可
for _, a := range section.axlePoints {
if !judgeKilometerIsVaild(a.KilometerSystem) {
return 0
}
length = a.KilometerSystem.Kilometer - length
}
return int32(math.Abs(float64(length)))
}
// 计算道岔端长度
func calcGraphicLenByTurnout(turnout *buildCalcTurnoutStruct, p graphicData.RelatedRef_DevicePort) int32 {
var endPoint *graphicData.AxleCounting
switch p {
case graphicData.RelatedRef_A:
endPoint = turnout.APoint
case graphicData.RelatedRef_B:
endPoint = turnout.BPoint
case graphicData.RelatedRef_C:
endPoint = turnout.CPoint
default:
zap.S().Warnf("道岔【%s】对应端口【%s】数据错误", turnout.Data.Common.Id, p.String())
endPoint := turnout.axlePoints[p]
if endPoint == nil || !judgeKilometerIsVaild(endPoint.KilometerSystem) {
zap.S().Warnf("道岔【%s】对应端口【%s】数据无计轴", turnout.Data.Common.Id, p.String())
return 0
}
if turnout.CrossKilometerSystem == nil {
if !judgeKilometerIsVaild(turnout.CrossKilometerSystem) {
zap.S().Warnf("道岔【%s】数据错误,岔心公里标为空", turnout.Data.Common.Id)
return 0
}
if endPoint == nil {
zap.S().Warnf("道岔【%s】数据错误,无计轴", turnout.Data.Common.Id)
return 0
}
start := turnout.CrossKilometerSystem.Kilometer
end := endPoint.KilometerSystem.Kilometer
if end > start {
return int32(end - start)
} else {
return int32(start - end)
}
return int32(math.Abs(float64(end - start)))
}
// 获取关于区段的设备信息
func getGraphicSectionRefDevices(deviceMap map[string]*graphicData.CalculateLink_DevicePosition, section *buildCalcSectionStruct, offset int32, prevKm int64) (int32, int64) {
// 目前只放入区段两端的信息
if section.APoint != nil && deviceMap[section.APoint.Common.Id] == nil {
offset = offset + int32(section.APoint.KilometerSystem.Kilometer-prevKm)
prevKm = section.APoint.KilometerSystem.Kilometer
deviceMap[section.APoint.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: section.APoint.Common.Id,
Offset: offset,
func getGraphicSectionRefDevices(refVal *graphicData.RelatedRef, deviceMap map[string]*graphicData.CalculateLink_DevicePosition,
section *buildCalcSectionStruct, offset int32, prevKm int64) (int32, int64) {
dealFunc := func(p *graphicData.AxleCounting, d map[string]*graphicData.CalculateLink_DevicePosition, o int32, pk int64) (int32, int64) {
if p != nil && deviceMap[p.Common.Id] == nil {
resultOff := o + int32(math.Abs(float64(p.KilometerSystem.Kilometer-pk)))
resultPK := p.KilometerSystem.Kilometer
deviceMap[p.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: p.Common.Id,
Offset: resultOff,
DeviceType: graphicData.RelatedRef_AxleCounting.String(),
}
return resultOff, resultPK
}
return o, pk
}
// 查看连接点
point := section.axlePoints[refVal.DevicePort]
offsetCalc, prevKmCalc := offset, prevKm
offsetCalc, prevKmCalc = dealFunc(point, deviceMap, offsetCalc, prevKmCalc)
// 获取另一个连接点
nextPoint := graphicData.RelatedRef_B
if refVal.DevicePort == nextPoint {
nextPoint = graphicData.RelatedRef_A
}
point = section.axlePoints[nextPoint]
offsetCalc, prevKmCalc = dealFunc(point, deviceMap, offsetCalc, prevKmCalc)
// 处理区段上的设备
startPoint := section.axlePoints[refVal.DevicePort]
if startPoint != nil {
sppk := startPoint.KilometerSystem.Kilometer // 相对起点的公里标
spof := deviceMap[startPoint.Common.Id].Offset // 相对的起点offset
// 信号机信息
for _, s := range section.signals {
if judgeKilometerIsVaild(s.KilometerSystem) && deviceMap[s.Common.Id] == nil {
deviceMap[s.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: s.Common.Id,
Offset: spof + int32(math.Abs(float64(s.KilometerSystem.Kilometer-sppk))),
DeviceType: "Signal",
}
}
if section.BPoint != nil && deviceMap[section.BPoint.Common.Id] == nil {
offset = offset + int32(section.BPoint.KilometerSystem.Kilometer-prevKm)
prevKm = section.BPoint.KilometerSystem.Kilometer
deviceMap[section.BPoint.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: section.BPoint.Common.Id,
Offset: offset,
}
// 停车标信息
for _, s := range section.stopPositions {
if judgeKilometerIsVaild(s.KilometerSystem) && deviceMap[s.Common.Id] == nil {
deviceMap[s.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: s.Common.Id,
Offset: spof + int32(math.Abs(float64(s.KilometerSystem.Kilometer-sppk))),
DeviceType: "StopPosition",
}
}
return offset, prevKm
}
// 应答器信息
for _, t := range section.transponders {
if judgeKilometerIsVaild(t.KilometerSystem) && deviceMap[t.Common.Id] == nil {
deviceMap[t.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: t.Common.Id,
Offset: spof + int32(math.Abs(float64(t.KilometerSystem.Kilometer-sppk))),
DeviceType: "Transponder",
}
}
}
// 坡度
for id, s := range section.slopes {
if judgeKilometerIsVaild(s) && deviceMap[id] == nil {
deviceMap[id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: id,
Offset: spof + int32(math.Abs(float64(s.Kilometer-sppk))),
DeviceType: "slopes",
}
}
}
// 曲度
for id, c := range section.curvatures {
if judgeKilometerIsVaild(c) && deviceMap[id] == nil {
deviceMap[id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: id,
Offset: spof + int32(math.Abs(float64(c.Kilometer-sppk))),
DeviceType: "curvatures",
}
}
}
}
return offsetCalc, prevKmCalc
}
// 获取关于道岔的设备信息
func getGraphicTurnoutRefDevices(deviceMap map[string]*graphicData.CalculateLink_DevicePosition, turnout *buildCalcTurnoutStruct, offset int32, prevKm int64) (int32, int64) {
func getGraphicTurnoutRefDevices(refVal *graphicData.RelatedRef, deviceMap map[string]*graphicData.CalculateLink_DevicePosition, turnout *buildCalcTurnoutStruct, offset int32, prevKm int64) (int32, int64) {
// 目前只放入岔心位置
if turnout.CrossKilometerSystem != nil && deviceMap[turnout.Data.Common.Id] == nil {
offset = offset + int32(turnout.CrossKilometerSystem.Kilometer-prevKm)
prevKm = turnout.CrossKilometerSystem.Kilometer
offsetCalc := offset + int32(math.Abs(float64(turnout.CrossKilometerSystem.Kilometer-prevKm)))
prevKmCalc := turnout.CrossKilometerSystem.Kilometer
deviceMap[turnout.Data.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: turnout.Data.Common.Id,
Offset: offset,
Offset: offsetCalc,
DeviceType: graphicData.RelatedRef_Turnout.String(),
}
// 查看是否存在连接计轴
point := turnout.axlePoints[refVal.DevicePort]
if point != nil && judgeKilometerIsVaild(point.KilometerSystem) && deviceMap[point.Common.Id] == nil {
deviceMap[point.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: point.Common.Id,
Offset: offset + int32(math.Abs(float64(point.KilometerSystem.Kilometer-prevKm))),
DeviceType: graphicData.RelatedRef_AxleCounting.String(),
}
}
// 处理道岔上的信号机
signal := turnout.signals[refVal.DevicePort]
if signal != nil && judgeKilometerIsVaild(signal.KilometerSystem) && deviceMap[signal.Common.Id] == nil {
deviceMap[signal.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: signal.Common.Id,
Offset: offset + int32(math.Abs(float64(signal.KilometerSystem.Kilometer-prevKm))),
DeviceType: "Signal",
}
}
// 处理道岔上的应答器
transponders := turnout.transponders[refVal.DevicePort]
if transponders != nil {
for _, t := range transponders {
if judgeKilometerIsVaild(t.KilometerSystem) && deviceMap[t.Common.Id] == nil {
deviceMap[t.Common.Id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: t.Common.Id,
Offset: offset + int32(math.Abs(float64(t.KilometerSystem.Kilometer-prevKm))),
DeviceType: "Transponder",
}
}
}
return offset, prevKm
}
// 获取区段的对应端
func getGraphicSectionPointRef(section *buildCalcSectionStruct, b bool, defaultRelateRef *graphicData.RelatedRef) *graphicData.RelatedRef {
if section.APoint == nil || section.BPoint == nil {
return defaultRelateRef
// 坡度
sm := turnout.slopes[refVal.DevicePort]
if sm != nil {
for id, s := range sm {
if judgeKilometerIsVaild(s) && deviceMap[id] == nil {
deviceMap[id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: id,
Offset: offset + int32(math.Abs(float64(s.Kilometer-prevKm))),
DeviceType: "slopes",
}
if section.APoint.KilometerSystem.Kilometer < section.BPoint.KilometerSystem.Kilometer && b {
return &graphicData.RelatedRef{DeviceType: graphicData.RelatedRef_Section, Id: section.Data.Common.Id, DevicePort: graphicData.RelatedRef_A}
} else {
return &graphicData.RelatedRef{DeviceType: graphicData.RelatedRef_Section, Id: section.Data.Common.Id, DevicePort: graphicData.RelatedRef_B}
}
}
}
// 曲度
cm := turnout.curvatures[refVal.DevicePort]
if cm != nil {
for id, c := range cm {
if judgeKilometerIsVaild(c) && deviceMap[id] == nil {
deviceMap[id] = &graphicData.CalculateLink_DevicePosition{
DeviceId: id,
Offset: offset + int32(math.Abs(float64(c.Kilometer-prevKm))),
DeviceType: "curvatures",
}
}
}
}
return offsetCalc, prevKmCalc
}
return offset, prevKm
}
// 获取link的起始点和包装数据结构方便查找以道岔的各分支的连接点为起点
func getGraphicDataDeviceMap(gd *graphicData.RtssGraphicStorage) (*buildCalcStruct, *list.List) {
@ -202,7 +306,7 @@ func getGraphicDataDeviceMap(gd *graphicData.RtssGraphicStorage) (*buildCalcStru
for _, t := range gd.Turnouts {
var op *graphicData.KilometerSystem
for _, k := range t.KilometerSystem {
if k.CoordinateSystem == "MAIN_LINE" && k.Kilometer != 0 {
if judgeKilometerIsVaild(k) {
op = k
}
}
@ -215,33 +319,114 @@ func getGraphicDataDeviceMap(gd *graphicData.RtssGraphicStorage) (*buildCalcStru
if t.PcRef != nil {
startPoints.PushBack(t.PcRef)
}
gm.TurnoutMap[t.Common.Id] = &buildCalcTurnoutStruct{Data: t, CrossKilometerSystem: op}
gm.TurnoutMap[t.Common.Id] = &buildCalcTurnoutStruct{
Data: t,
CrossKilometerSystem: op,
axlePoints: make(map[graphicData.RelatedRef_DevicePort]*graphicData.AxleCounting),
transponders: make(map[graphicData.RelatedRef_DevicePort][]*graphicData.Transponder),
signals: make(map[graphicData.RelatedRef_DevicePort]*graphicData.Signal),
slopes: make(map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem),
curvatures: make(map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem),
}
}
// 区段列表
for _, s := range gd.Section {
gm.SectionMap[s.Common.Id] = &buildCalcSectionStruct{Data: s}
gm.SectionMap[s.Common.Id] = &buildCalcSectionStruct{
Data: s,
axlePoints: make(map[graphicData.RelatedRef_DevicePort]*graphicData.AxleCounting),
slopes: make(map[string]*graphicData.KilometerSystem),
curvatures: make(map[string]*graphicData.KilometerSystem),
}
}
// 计轴点关联到对应的区段,道岔上
for _, a := range gd.AxleCountings {
gm.AxlePointMap[a.Common.Id] = a
for _, r := range a.AxleCountingRef {
if r.DeviceType == graphicData.RelatedRef_Section {
section := gm.SectionMap[r.Id]
if r.DevicePort == graphicData.RelatedRef_A {
section.APoint = a
} else if r.DevicePort == graphicData.RelatedRef_B {
section.BPoint = a
}
gm.SectionMap[r.Id].axlePoints[r.DevicePort] = a
} else if r.DeviceType == graphicData.RelatedRef_Turnout {
if r.DevicePort == graphicData.RelatedRef_A {
gm.TurnoutMap[r.Id].APoint = a
} else if r.DevicePort == graphicData.RelatedRef_B {
gm.TurnoutMap[r.Id].BPoint = a
} else {
gm.TurnoutMap[r.Id].CPoint = a
gm.TurnoutMap[r.Id].axlePoints[r.DevicePort] = a
}
}
}
// 信号机关联到对应区段或道岔上
for _, s := range gd.Signals {
// 过滤掉没有公里标数据的信号机
if !judgeKilometerIsVaild(s.KilometerSystem) {
continue
}
switch s.RefDev.DeviceType {
case graphicData.RelatedRef_Section:
gm.SectionMap[s.RefDev.Id].signals = append(gm.SectionMap[s.RefDev.Id].signals, s)
case graphicData.RelatedRef_Turnout:
gm.TurnoutMap[s.RefDev.Id].signals[s.RefDev.DevicePort] = s
}
}
// 应答器关联到对应区段或道岔
for _, t := range gd.Transponders {
// 过滤掉没有公里标数据的应答器
if !judgeKilometerIsVaild(t.KilometerSystem) {
continue
}
switch t.TransponderRef.DeviceType {
case graphicData.RelatedRef_Section:
gm.SectionMap[t.TransponderRef.Id].transponders = append(gm.SectionMap[t.TransponderRef.Id].transponders, t)
case graphicData.RelatedRef_Turnout:
gm.TurnoutMap[t.TransponderRef.Id].transponders[t.TransponderRef.DevicePort] = append(gm.TurnoutMap[t.TransponderRef.Id].transponders[t.TransponderRef.DevicePort], t)
}
}
// 停车标关联到对应区段或道岔
for _, s := range gd.StopPositions {
// 过滤掉没有公里标数据的停车标
if !judgeKilometerIsVaild(s.KilometerSystem) {
continue
}
switch s.RefDev.DeviceType {
case graphicData.RelatedRef_Section:
gm.SectionMap[s.RefDev.Id].stopPositions = append(gm.SectionMap[s.RefDev.Id].stopPositions, s)
}
}
// 坡度Map
slopeMap := make(map[graphicData.Direction]map[string]*graphicData.KilometerSystem)
for _, s := range gd.SlopeKiloMarker {
handleSlopeCurvaturesMap(s.Common.Id, s.KilometerSystem, slopeMap)
}
// 曲度Map
curvatureMap := make(map[graphicData.Direction]map[string]*graphicData.KilometerSystem)
for _, c := range gd.CurvatureKiloMarker {
handleSlopeCurvaturesMap(c.Common.Id, c.KilometerSystem, curvatureMap)
}
if len(slopeMap) != 0 || len(curvatureMap) != 0 {
for _, s := range gm.SectionMap {
handleSectionSlopeCurvaturesMap(s, slopeMap, func(sec *buildCalcSectionStruct) map[string]*graphicData.KilometerSystem { return sec.slopes })
handleSectionSlopeCurvaturesMap(s, curvatureMap, func(sec *buildCalcSectionStruct) map[string]*graphicData.KilometerSystem { return sec.curvatures })
}
for _, t := range gm.TurnoutMap {
if !judgeKilometerIsVaild(t.CrossKilometerSystem) {
continue
}
// A点坡度
handleTurnoutSlopeCurvaturesMap(graphicData.RelatedRef_A, t, slopeMap,
func(sw *buildCalcTurnoutStruct) map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem {
return sw.slopes
})
// B点坡度
handleTurnoutSlopeCurvaturesMap(graphicData.RelatedRef_B, t, slopeMap,
func(sw *buildCalcTurnoutStruct) map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem {
return sw.slopes
})
// A点曲度
handleTurnoutSlopeCurvaturesMap(graphicData.RelatedRef_A, t, curvatureMap,
func(sw *buildCalcTurnoutStruct) map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem {
return sw.curvatures
})
// B点曲度
handleTurnoutSlopeCurvaturesMap(graphicData.RelatedRef_B, t, curvatureMap,
func(sw *buildCalcTurnoutStruct) map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem {
return sw.curvatures
})
}
}
return gm, startPoints
}
@ -257,9 +442,11 @@ func getGraphicLinkPath(gm *buildCalcStruct, startPointQueue *list.List) map[int
var refInfo *graphicData.RelatedRef
var axleInfo *graphicData.AxleCounting
if relatedRef.DeviceType == graphicData.RelatedRef_Section {
refInfo, axleInfo = getRelatePointInfo(reflect.ValueOf(gm.SectionMap[relatedRef.Id]).Elem(), relatedRef.DevicePort)
axleInfo = gm.SectionMap[relatedRef.Id].axlePoints[relatedRef.DevicePort]
refInfo = getRelatePointInfo(reflect.ValueOf(gm.SectionMap[relatedRef.Id]).Elem(), relatedRef.DevicePort)
} else {
refInfo, axleInfo = getRelatePointInfo(reflect.ValueOf(gm.TurnoutMap[relatedRef.Id]).Elem(), relatedRef.DevicePort)
axleInfo = gm.TurnoutMap[relatedRef.Id].axlePoints[relatedRef.DevicePort]
refInfo = getRelatePointInfo(reflect.ValueOf(gm.TurnoutMap[relatedRef.Id]).Elem(), relatedRef.DevicePort)
}
// 查看是否已经被处理过的ID计轴信息为空时表示道岔将ID排序后存入
var handleId string
@ -274,37 +461,23 @@ func getGraphicLinkPath(gm *buildCalcStruct, startPointQueue *list.List) map[int
continue
}
handleMap[handleId] = true
// 追加函数存在问题,表示数据存在问题
appendFunc := getRelateAppendMethod(gm, refInfo, relatedRef)
if appendFunc == nil {
zap.S().Warnf("link设备【%s】追加方式不确定", relatedRef.Id)
continue
}
pathRefArr := []*graphicData.RelatedRef{refInfo}
// 循环查找结束点
loopRelateRef := relatedRef
for loopRelateRef != nil {
pathRefArr = appendFunc(loopRelateRef, pathRefArr)
pathRefArr = append(pathRefArr, loopRelateRef)
switch loopRelateRef.DeviceType {
case graphicData.RelatedRef_Section:
section := gm.SectionMap[loopRelateRef.Id]
axleInfo = section.axlePoints[loopRelateRef.DevicePort]
if loopRelateRef.DevicePort == graphicData.RelatedRef_A {
axleInfo = section.BPoint
loopRelateRef = section.Data.PbRef
} else {
axleInfo = section.APoint
loopRelateRef = section.Data.PaRef
}
case graphicData.RelatedRef_Turnout:
turnout := gm.TurnoutMap[loopRelateRef.Id]
switch loopRelateRef.DevicePort {
case graphicData.RelatedRef_A:
axleInfo = turnout.APoint
case graphicData.RelatedRef_B:
axleInfo = turnout.BPoint
case graphicData.RelatedRef_C:
axleInfo = turnout.CPoint
}
axleInfo = turnout.axlePoints[loopRelateRef.DevicePort]
loopRelateRef = nil
}
if axleInfo != nil { // 放入处理的计轴,防止倒过来重复处理
@ -314,77 +487,22 @@ func getGraphicLinkPath(gm *buildCalcStruct, startPointQueue *list.List) map[int
resultMap[id] = pathRefArr
id++ // ID自增
}
fmt.Println(resultMap)
return resultMap
}
// 获取本连接点上一个连接信息以及计轴信息
func getRelatePointInfo(v reflect.Value, p graphicData.RelatedRef_DevicePort) (*graphicData.RelatedRef, *graphicData.AxleCounting) {
func getRelatePointInfo(v reflect.Value, p graphicData.RelatedRef_DevicePort) *graphicData.RelatedRef {
var relateInfo reflect.Value
var axlePoint reflect.Value
// 放入计轴点
switch p {
case graphicData.RelatedRef_A:
relateInfo = v.FieldByName("Data").Elem().FieldByName("PaRef")
axlePoint = v.FieldByName("APoint")
case graphicData.RelatedRef_B:
relateInfo = v.FieldByName("Data").Elem().FieldByName("PbRef")
axlePoint = v.FieldByName("BPoint")
case graphicData.RelatedRef_C:
relateInfo = v.FieldByName("Data").Elem().FieldByName("PcRef")
axlePoint = v.FieldByName("CPoint")
}
return relateInfo.Interface().(*graphicData.RelatedRef), axlePoint.Interface().(*graphicData.AxleCounting)
}
// 确定接点追加方法
func getRelateAppendMethod(gm *buildCalcStruct, sRef, eRef *graphicData.RelatedRef) func(*graphicData.RelatedRef, []*graphicData.RelatedRef) []*graphicData.RelatedRef {
start, sOK := handleFunc(gm, sRef)
if !sOK {
return nil
}
end, eOk := handleFunc(gm, eRef)
if !eOk {
return nil
}
if start > end {
return func(refInfo *graphicData.RelatedRef, linkArr []*graphicData.RelatedRef) []*graphicData.RelatedRef {
return append([]*graphicData.RelatedRef{refInfo}, linkArr...)
}
} else {
return func(refInfo *graphicData.RelatedRef, linkArr []*graphicData.RelatedRef) []*graphicData.RelatedRef {
return append(linkArr, refInfo)
}
}
}
// 处理函数
func handleFunc(gm *buildCalcStruct, ref *graphicData.RelatedRef) (int, bool) {
switch ref.DeviceType {
case graphicData.RelatedRef_Section:
section := gm.SectionMap[ref.Id]
if ref.DevicePort == graphicData.RelatedRef_A {
if section.APoint == nil || section.APoint.KilometerSystem == nil {
zap.S().Warnf("区段【%s】A端缺少关联计轴信息", ref.Id)
} else {
return int(section.APoint.KilometerSystem.Kilometer), true
}
} else {
if section.BPoint == nil || section.BPoint.KilometerSystem == nil {
zap.S().Warnf("区段【%s】B端缺少关联计轴信息", ref.Id)
} else {
return int(section.BPoint.KilometerSystem.Kilometer), true
}
}
case graphicData.RelatedRef_Turnout:
turnout := gm.TurnoutMap[ref.Id]
if turnout.CrossKilometerSystem == nil {
zap.S().Warnf("道岔【%s】缺少岔心公里标数据", ref.Id)
} else {
return int(turnout.CrossKilometerSystem.Kilometer), true
}
}
return 0, false
return relateInfo.Interface().(*graphicData.RelatedRef)
}
// 获取起始端的
@ -392,25 +510,97 @@ func getStartKilometer(gm *buildCalcStruct, ref *graphicData.RelatedRef) (int64,
switch ref.DeviceType {
case graphicData.RelatedRef_Section:
section := gm.SectionMap[ref.Id]
var aKilometer = int64(math.MaxInt64)
if section.APoint != nil {
aKilometer = section.APoint.KilometerSystem.Kilometer
var resultKilometer = int64(math.MaxInt64)
for _, p := range section.axlePoints {
if resultKilometer > p.KilometerSystem.Kilometer {
resultKilometer = p.KilometerSystem.Kilometer
}
var bKilometer = int64(math.MaxInt64)
if section.BPoint != nil {
bKilometer = section.APoint.KilometerSystem.Kilometer
}
if aKilometer > bKilometer {
return bKilometer, 0
} else {
return bKilometer, 0
if resultKilometer == math.MaxInt64 {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "区段公里标数据出错"})
}
return resultKilometer, 0
case graphicData.RelatedRef_Turnout:
turnout := gm.TurnoutMap[ref.Id]
if turnout.CrossKilometerSystem == nil {
if !judgeKilometerIsVaild(turnout.CrossKilometerSystem) {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "道岔岔心无公里标"})
}
return turnout.CrossKilometerSystem.Kilometer, 0
}
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "错误的设备类型类型"})
}
// 判断公里标是否有效
func judgeKilometerIsVaild(k *graphicData.KilometerSystem) bool {
return k != nil && k.CoordinateSystem == "MAIN_LINE" && k.Kilometer != 0
}
// 判断公里标k1 是否在这k2,k3个范围内
func judgeKilometerInRange(k1, k2, k3 *graphicData.KilometerSystem) bool {
if judgeKilometerIsVaild(k1) && judgeKilometerIsVaild(k2) && judgeKilometerIsVaild(k3) {
start, end := k2, k3
if k2.Kilometer > k3.Kilometer {
start, end = k3, k2
}
return k1.Kilometer > start.Kilometer && k1.Kilometer < end.Kilometer
}
return false
}
// 处理道岔坡度、曲度信息
func handleSlopeCurvaturesMap(id string, kms []*graphicData.KilometerSystem, m map[graphicData.Direction]map[string]*graphicData.KilometerSystem) {
for _, k := range kms {
if judgeKilometerIsVaild(k) {
kmMap := m[k.Direction]
if kmMap == nil {
kmMap = make(map[string]*graphicData.KilometerSystem)
m[k.Direction] = kmMap
}
kmMap[id] = k
}
}
}
func handleTurnoutSlopeCurvaturesMap(port graphicData.RelatedRef_DevicePort,
t *buildCalcTurnoutStruct,
scmap map[graphicData.Direction]map[string]*graphicData.KilometerSystem,
f func(*buildCalcTurnoutStruct) map[graphicData.RelatedRef_DevicePort]map[string]*graphicData.KilometerSystem) {
point := t.axlePoints[port]
if point != nil {
m := f(t)
m[port] = make(map[string]*graphicData.KilometerSystem)
kmMap := scmap[point.KilometerSystem.Direction]
idArr := []string{}
for k, v := range kmMap {
if judgeKilometerInRange(v, point.KilometerSystem, t.CrossKilometerSystem) {
m[port][k] = v
idArr = append(idArr, k)
}
}
for _, id := range idArr {
delete(kmMap, id)
}
}
}
func handleSectionSlopeCurvaturesMap(s *buildCalcSectionStruct,
scmap map[graphicData.Direction]map[string]*graphicData.KilometerSystem,
f func(*buildCalcSectionStruct) map[string]*graphicData.KilometerSystem) {
pointA := s.axlePoints[graphicData.RelatedRef_A]
pointB := s.axlePoints[graphicData.RelatedRef_B]
if pointA == nil || pointB == nil {
return
}
m := f(s)
kmMap := scmap[pointA.KilometerSystem.Direction]
idArr := []string{}
for k, v := range kmMap {
if judgeKilometerInRange(v, pointA.KilometerSystem, pointB.KilometerSystem) {
m[k] = v
idArr = append(idArr, k)
}
}
for _, id := range idArr {
delete(kmMap, id)
}
}

View File

@ -3,6 +3,8 @@ package memory
import (
"container/list"
"fmt"
"math"
"sort"
"strconv"
"sync"
@ -13,13 +15,15 @@ import (
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/device"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/ref"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/section"
"joylink.club/bj-rtsts-server/db/dbquery"
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
)
// 仿真存储集合 ID
var graphicDataMap sync.Map
// 轨旁仿真模型结构,注意这里的key 为 Index
// VerifyStructure 轨旁仿真模型结构
type VerifyStructure struct {
//计轴检测点设备模型集合,key为索引编号
AxlePointDeviceModelMap map[string]face.AxlePointDeviceModeller
@ -35,18 +39,37 @@ type VerifyStructure struct {
LogicalSectionModelMap map[string]face.LogicalSectionModeller
//信号机模型集合,key为索引编号
SignalDeviceModelMap map[string]face.SignalDeviceModeller
//Link模型集合key为索引编号
LinkModelMap map[int32]*device.LinkModel
//坡度模型集合key为id
SlopeModelMap map[string]*section.SlopeModel
//曲线模型集合key为id
CurveModelMap map[string]*section.CurveModel
//点模型集合key为id
PointMap map[string]*device.PointModel
}
// 设备地图ID对应map结构体(建立关系时便于查找使用)注意这里的key 为 Common.Id
// GraphicInfoMapStructure 设备地图ID对应map结构体(建立关系时便于查找使用)
type GraphicInfoMapStructure struct {
AxlePointMap map[string]*graphicData.AxleCounting
TurnoutMap map[string]*graphicData.Turnout
LinkMap map[string]*graphicData.SectionLink
SectionLinkMap map[string]*graphicData.SectionLink
AxleSectionMap map[string]*graphicData.AxleCountingSection
PhysicalSectionMap map[string]*graphicData.Section
LogicSectionMap map[string]*graphicData.LogicSection
SignalMap map[string]*graphicData.Signal
CalcLinkMap map[string]*graphicData.CalculateLink
//key-index
CalcLinkMap map[int32]*graphicData.CalculateLink
//设备在link上的位置。key-设备id
DevicePositionMap map[string]*ref.DevicePosition
}
// 计算link、物理区段、道岔相互转换时用到的结构体
type calcLinkPositionStruct struct {
index string // 地图元素的Index
deviceType int // 1 计轴, 2 道岔
kilometer *graphicData.KilometerSystem // 元素对应的公里标
position *ref.DevicePosition // 元素在link上对应的偏移量
}
// 将发布的地图数据放入内存中
@ -60,24 +83,29 @@ func PublishMapVerifyStructure(graphic *model.PublishedGi) *VerifyStructure {
PhysicalSectionModelMap: make(map[string]face.PhysicalSectionModeller),
LogicalSectionModelMap: make(map[string]face.LogicalSectionModeller),
SignalDeviceModelMap: make(map[string]face.SignalDeviceModeller),
LinkModelMap: make(map[int32]*device.LinkModel),
SlopeModelMap: make(map[string]*section.SlopeModel),
CurveModelMap: make(map[string]*section.CurveModel),
PointMap: make(map[string]*device.PointModel),
}
// 地图数据转为map存储建立关系时方便使用
graphicInfoMap := &GraphicInfoMapStructure{
AxlePointMap: make(map[string]*graphicData.AxleCounting),
TurnoutMap: make(map[string]*graphicData.Turnout),
LinkMap: make(map[string]*graphicData.SectionLink),
SectionLinkMap: make(map[string]*graphicData.SectionLink),
AxleSectionMap: make(map[string]*graphicData.AxleCountingSection),
PhysicalSectionMap: make(map[string]*graphicData.Section),
LogicSectionMap: make(map[string]*graphicData.LogicSection),
SignalMap: make(map[string]*graphicData.Signal),
CalcLinkMap: make(map[string]*graphicData.CalculateLink),
CalcLinkMap: make(map[int32]*graphicData.CalculateLink),
DevicePositionMap: make(map[string]*ref.DevicePosition),
}
graphicStorage := &graphicData.RtssGraphicStorage{}
proto.Unmarshal(graphic.Proto, graphicStorage)
// 初始化地图结构
initGraphicStructure(graphicStorage, verifyStructure, graphicInfoMap)
// 构建设备间的关联关系(8.8 注释掉构建逻辑)
// buildDeviceRef(graphicInfoMap, verifyStructure)
buildDeviceRef(graphicInfoMap, verifyStructure)
graphicDataMap.Store(graphic.ID, verifyStructure)
return verifyStructure
}
@ -93,8 +121,230 @@ func QueryMapVerifyStructure(mapId int32) *VerifyStructure {
if ok {
return d.(*VerifyStructure)
}
mapData, _ := dbquery.PublishedGi.Where(dbquery.PublishedGi.ID.Eq(mapId), dbquery.PublishedGi.Status.Eq(1)).First()
if mapData != nil {
return PublishMapVerifyStructure(mapData)
} else {
panic(fmt.Sprintf("地图【id:%d】不存在", mapId))
}
}
// 根据区段道岔偏移量返回linkID和link相对偏移量
func QueryMapCalcLinkByDeviceInfo(mapId int32, id string, devicePort string, offset int64, runDirection bool) (int32, int64, bool, bool) {
vm := QueryMapVerifyStructure(mapId)
if devicePort == "" {
return sectionMapToLink(vm, id, offset, runDirection)
} else {
return turnoutMapToLink(vm, id, devicePort, offset, runDirection)
}
}
// 根据物理区段上的偏移量基于区段A端找到所在link的linkId与偏移量
func sectionMapToLink(vm *VerifyStructure, id string, offset int64, runDirection bool) (int32, int64, bool, bool) {
sm := vm.PhysicalSectionModelMap[id]
if sm == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("不存在区段【index:%s】", id)})
}
sectionModel := sm.(*section.PhysicalSectionModel)
// 确定link信息
var linkId int32
// 获取计轴信息
axlePointPositionMap := make(map[string]*ref.DevicePosition)
for k, lm := range vm.LinkModelMap {
for _, p := range lm.DevicePositions {
_, ok := p.Device.(*device.AxlePointDeviceModel)
if ok && sectionModel.AxlePoints[p.Device.GetIndex()] != nil {
axlePointPositionMap[p.Device.GetIndex()] = p
}
}
// 如果已经找到计轴则退出
if len(axlePointPositionMap) > 0 {
linkId = k
break
}
}
if len(axlePointPositionMap) == 0 { // 无计轴信息
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("未找到区段【id:%s,index:%s】所在link", sectionModel.GraphicId, id)})
}
pointA := sectionModel.PortAxlePoints[face.A.Name()] // 获取A计轴点
if pointA != nil {
ap := axlePointPositionMap[pointA.GetIndex()]
if ap == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("link【%d】缺失计轴【%s】", linkId, pointA.GetGraphicId())})
}
pointB := sectionModel.PortAxlePoints[face.B.Name()] // 获取B计轴点
abDirection := pointB == nil
ak := (pointA.(*device.AxlePointDeviceModel)).KilometerSystem // 获取a点公里标
ao, bo := ap.Offset, int32(math.MaxInt32) // ab的偏移量默认B点比A点大
var bp *ref.DevicePosition // 定义b点偏移对象
var bk *graphicData.KilometerSystem // 定义b点公里标
if !abDirection && axlePointPositionMap[pointB.GetIndex()] != nil {
bp = axlePointPositionMap[pointB.GetIndex()]
bo = bp.Offset
bk = (pointB.(*device.AxlePointDeviceModel)).KilometerSystem
abDirection = convertPointTo(ak, bk, runDirection)
}
up := convertRunDirectionToUp(ak, bk, ap, bp, runDirection)
if ao < bo {
return linkId, int64(ao) + offset, up, abDirection
} else {
return linkId, int64(ao) - offset, up, abDirection
}
} else {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("link【%d】缺失区段【id:%s,index:%s】A点缺失计轴", linkId, sectionModel.GraphicId, id)})
}
}
// 根据道岔上的偏移量基于岔心位置找到所在link的linkId与偏移量
func turnoutMapToLink(vm *VerifyStructure, id string, port string, offset int64, runDirection bool) (int32, int64, bool, bool) {
tm := vm.SwitchDeviceModelMap[id]
if tm == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("不存在道岔【index:%s】", id)})
}
turnoutModel := tm.(*device.SwitchDeviceModel)
var link *device.LinkModel
var linkId int32
var isStart bool
Outter:
for i, lm := range vm.LinkModelMap {
linkId = i
if lm.ARelatedSwitchRef.SwitchDevice != nil && lm.ARelatedSwitchRef.SwitchDevice.GetIndex() == turnoutModel.Index && lm.ARelatedSwitchRef.Port.Name() == port {
isStart = true
link = lm
} else if lm.BRelatedSwitchRef.SwitchDevice != nil && lm.BRelatedSwitchRef.SwitchDevice.GetIndex() == turnoutModel.Index && lm.BRelatedSwitchRef.Port.Name() == port {
link = lm
}
if link != nil {
break Outter
}
}
if link == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("未找到道岔【id:%s,index:%s】端口【%s】所在link", turnoutModel.GraphicId, id, port)})
}
calcPositionArr := convertPositionToCalcPosition(link)
var vp *calcLinkPositionStruct
var index int
for i, v := range calcPositionArr {
if v.index == turnoutModel.GetIndex() {
vp = v
index = i
break
}
}
if vp != nil && len(calcPositionArr) > 1 {
var np *calcLinkPositionStruct
if index+1 < len(calcPositionArr) {
np = calcPositionArr[index+1]
} else {
np = calcPositionArr[index-1]
}
up := convertRunDirectionToUp(vp.kilometer, np.kilometer, vp.position, np.position, runDirection)
pointTo := convertPointTo(vp.kilometer, np.kilometer, runDirection)
if isStart {
return linkId, int64(vp.position.Offset) + offset, up, pointTo
} else {
return linkId, int64(vp.position.Offset) - offset, up, pointTo
}
}
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("link【%d】缺失道岔【id:%s,index:%s】端口【%s】偏移量", linkId, turnoutModel.GraphicId, id, port)})
}
// 根据linkID和link相对偏移量返回区段道岔偏移量
// 设备ID、端口、偏移量、上下行、AB走向
func QueryDeviceByCalcLink(vm *VerifyStructure, id int32, offset int64, up, defaultRunDirection bool) (string, string, int64, bool, bool) {
linkModel := vm.LinkModelMap[id]
if linkModel == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("未找到link【%d】", id)})
}
if offset > int64(linkModel.Length) {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("偏移超出link范围【%d】", id)})
}
calcPositionArr := convertPositionToCalcPosition(linkModel) // 转换位置对象
var devicePosition, calcPosition *calcLinkPositionStruct // 获取当前、下一个节点,偏移量在这个范围中
for _, v := range calcPositionArr {
if v.position.Offset > int32(offset) {
calcPosition = v
break
} else {
devicePosition = v
}
}
// 运行方向
var runDirection bool
if calcPosition != nil {
runDirection = (calcPosition.kilometer.Kilometer >= devicePosition.kilometer.Kilometer) == up
} else {
runDirection = defaultRunDirection
}
isSwitch := (devicePosition.deviceType == 2) // 道岔
// 获取另一个端点
if calcPosition != nil {
isSwitch = isSwitch || calcPosition.deviceType == 2 // 道岔
}
if isSwitch {
var sid string
var op int64
if devicePosition.deviceType == 2 {
sid = devicePosition.index
op = int64(devicePosition.position.Offset)
} else {
sid = calcPosition.index
op = int64(calcPosition.position.Offset)
}
tm := vm.SwitchDeviceModelMap[sid]
if tm == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("不存在道岔【index:%s】", sid)})
}
if linkModel.ARelatedSwitchRef.SwitchDevice != nil && linkModel.ARelatedSwitchRef.SwitchDevice.GetIndex() == sid { // 起始点
return sid, linkModel.ARelatedSwitchRef.Port.Name(), offset - op, runDirection, up == false
} else if linkModel.BRelatedSwitchRef.SwitchDevice != nil && linkModel.BRelatedSwitchRef.SwitchDevice.GetIndex() == sid { // 结束点
return sid, linkModel.BRelatedSwitchRef.Port.Name(), op - offset, runDirection, up == true
} else {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("不存在道岔【index:%s】", devicePosition.index)})
}
} else {
sectionModel, ok := linkOffsetQuerySection(vm, devicePosition, calcPosition)
if ok {
isEnd := (calcPosition == nil) && (offset == int64(linkModel.Length)) // 是否已经走到尽头
pointA := sectionModel.PortAxlePoints[face.A.Name()]
var bk *graphicData.KilometerSystem
if calcPosition != nil {
bk = calcPosition.kilometer
}
if devicePosition.index == pointA.GetIndex() {
return sectionModel.Index, "", offset - int64(devicePosition.position.Offset), runDirection, convertPointTo(devicePosition.kilometer, bk, runDirection)
} else if calcPosition != nil {
return sectionModel.Index, "", int64(calcPosition.position.Offset) - offset, runDirection, convertPointTo(bk, devicePosition.kilometer, runDirection)
} else {
for _, v := range calcPositionArr {
if v.deviceType == 1 && v.index == pointA.GetIndex() { // 计轴
if isEnd {
return sectionModel.Index, "", offset - int64(v.position.Offset), runDirection, convertPointTo(v.kilometer, nil, runDirection)
} else {
return sectionModel.Index, "", int64(v.position.Offset) - offset, runDirection, convertPointTo(v.kilometer, devicePosition.kilometer, runDirection)
}
}
}
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("区段【%s】A端计轴缺失", sectionModel.GraphicId)})
}
} else {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("未找到区段【index:%s-index:%s】", devicePosition.index, calcPosition.index)})
}
}
}
func linkOffsetQuerySection(vm *VerifyStructure, devicePosition, calcPosition *calcLinkPositionStruct) (*section.PhysicalSectionModel, bool) {
var sectionModel *section.PhysicalSectionModel
for _, s := range vm.PhysicalSectionModelMap {
sectionModel = s.(*section.PhysicalSectionModel)
if sectionModel.AxlePoints[devicePosition.index] != nil && (calcPosition == nil || sectionModel.AxlePoints[calcPosition.index] != nil) {
return sectionModel, true
}
}
return nil, false
}
// 初始化地图结构
func initGraphicStructure(graphicData *graphicData.RtssGraphicStorage, verifyStructure *VerifyStructure, graphicDataMap *GraphicInfoMapStructure) {
@ -112,8 +362,134 @@ func initGraphicStructure(graphicData *graphicData.RtssGraphicStorage, verifyStr
initGraphicLogicSections(graphicData.LogicSections, verifyStructure, graphicDataMap)
// 初始化信号机信息
initGraphicSignal(graphicData.Signals, verifyStructure, graphicDataMap)
// 初始化计算link数据
initCalcLink(graphicData.CalculateLink, verifyStructure, graphicDataMap)
// 初始化Link信息
initLinks(graphicData.CalculateLink, verifyStructure, graphicDataMap)
// 初始化坡度和曲线端点
// initPoints(graphicData, verifyStructure, graphicDataMap)
// 初始化坡度
// initSlopes(graphicData.Slopes, verifyStructure, graphicDataMap)
// 初始化曲线
// initCurves(graphicData.Curvatures, verifyStructure, graphicDataMap)
}
func initCurves(curves []*graphicData.Curvature, vs *VerifyStructure, dataMap *GraphicInfoMapStructure) {
for _, curve := range curves {
startDp := dataMap.DevicePositionMap[curve.RefDeviceId[0]]
endDp := dataMap.DevicePositionMap[curve.RefDeviceId[1]]
startIndex, _ := strconv.Atoi(startDp.Device.GetIndex())
endIndex, _ := strconv.Atoi(endDp.Device.GetIndex())
vs.CurveModelMap[curve.Common.Id] = &section.CurveModel{
DeviceModel: face.DeviceModel{
GraphicId: curve.GetCommon().GetId(),
Index: curve.GetCommon().GetId(),
},
StartLinkIndex: int32(startIndex),
StartLinkOffset: startDp.Offset,
EndLinkIndex: int32(endIndex),
EndLinkOffset: endDp.Offset,
Curvature: curve.CurvatureNumber,
}
}
}
func initSlopes(slopes []*graphicData.Slope, vs *VerifyStructure, dataMap *GraphicInfoMapStructure) {
for _, slope := range slopes {
startDp := dataMap.DevicePositionMap[slope.RefDeviceId[0]]
endDp := dataMap.DevicePositionMap[slope.RefDeviceId[1]]
startIndex, _ := strconv.Atoi(startDp.Device.GetIndex())
endIndex, _ := strconv.Atoi(endDp.Device.GetIndex())
vs.SlopeModelMap[slope.Common.Id] = &section.SlopeModel{
DeviceModel: face.DeviceModel{
GraphicId: slope.GetCommon().GetId(),
Index: slope.GetCommon().GetId(),
},
StartLinkIndex: int32(startIndex),
StartLinkOffset: startDp.Offset,
EndLinkIndex: int32(endIndex),
EndLinkOffset: endDp.Offset,
DegreeTrig: slope.SlopeNumber,
}
}
}
func initPoints(storage *graphicData.RtssGraphicStorage, vs *VerifyStructure, dataMap *GraphicInfoMapStructure) {
for _, slopeKm := range storage.SlopeKiloMarker {
vs.PointMap[slopeKm.Common.Id] = &device.PointModel{
DeviceModel: face.DeviceModel{
GraphicId: slopeKm.Common.Id,
Index: slopeKm.Common.Id,
},
Kms: slopeKm.KilometerSystem,
}
}
for _, curvatureKm := range storage.CurvatureKiloMarker {
vs.PointMap[curvatureKm.Common.Id] = &device.PointModel{
DeviceModel: face.DeviceModel{
GraphicId: curvatureKm.Common.Id,
Index: curvatureKm.Common.Id,
},
Kms: curvatureKm.KilometerSystem,
}
}
}
func initLinks(links []*graphicData.CalculateLink, vs *VerifyStructure, dataMap *GraphicInfoMapStructure) {
deviceIdMap := make(map[string]face.DeviceModeller)
for _, modeller := range vs.AxlePointDeviceModelMap {
deviceIdMap[modeller.GetGraphicId()] = modeller
}
for _, modeller := range vs.SwitchDeviceModelMap {
deviceIdMap[modeller.GetGraphicId()] = modeller
}
for _, pointModel := range vs.PointMap {
deviceIdMap[pointModel.GetGraphicId()] = pointModel
}
for _, link := range links {
linkModel := &device.LinkModel{
DeviceModel: face.DeviceModel{
GraphicId: link.Common.Id,
Index: strconv.Itoa(int(link.Index)),
},
Length: link.Length,
}
if link.ARelatedRef != nil {
linkModel.ARelatedSwitchRef = ref.SwitchRef{
SwitchDevice: deviceIdMap[link.ARelatedRef.Id],
Port: face.GetPortEnum(int8(link.ARelatedRef.DevicePort)),
}
}
if link.BRelatedRef != nil {
linkModel.BRelatedSwitchRef = ref.SwitchRef{
SwitchDevice: deviceIdMap[link.BRelatedRef.Id],
Port: face.GetPortEnum(int8(link.BRelatedRef.DevicePort)),
}
}
vs.LinkModelMap[link.Index] = linkModel
dataMap.CalcLinkMap[link.Index] = link
//构建DevicePositionDP切片(暂时仅计轴和道岔)
var dps []*ref.DevicePosition
for _, dp := range link.DevicePositions {
modeller := deviceIdMap[dp.DeviceId]
if modeller == nil {
continue
}
dps = append(dps, &ref.DevicePosition{
Device: modeller,
Offset: dp.Offset,
})
dataMap.DevicePositionMap[dp.DeviceId] = &ref.DevicePosition{
Device: linkModel,
Offset: dp.Offset,
}
}
//对DP切片按Offset排序
sort.Slice(dps, func(i, j int) bool {
return dps[i].Offset < dps[j].Offset
})
//赋值
linkModel.DevicePositions = dps
}
}
// 初始化计轴信息
@ -126,7 +502,7 @@ func initGraphicAxlePoints(axlePoints []*graphicData.AxleCounting, data *VerifyS
GraphicId: a.Common.Id,
Index: id,
},
KilometerSystem: *a.GetKilometerSystem(),
KilometerSystem: a.GetKilometerSystem(),
SwitchDevices: make(map[string]*ref.SwitchRef),
AreaPhysicalSections: make(map[string]face.PhysicalSectionModeller),
}
@ -144,6 +520,7 @@ func initGraphicTurnout(turnouts []*graphicData.Turnout, data *VerifyStructure,
Index: id,
},
KilometerSystems: t.GetKilometerSystem(),
AxlePoints: make(map[string]*device.AxlePointDeviceModel),
}
}
}
@ -151,7 +528,7 @@ func initGraphicTurnout(turnouts []*graphicData.Turnout, data *VerifyStructure,
// 初始化link信息
func initGraphicLink(links []*graphicData.SectionLink, data *VerifyStructure, graphicDataMap *GraphicInfoMapStructure) {
for _, s := range links {
graphicDataMap.LinkMap[s.Common.Id] = s
graphicDataMap.SectionLinkMap[s.Common.Id] = s
id := strconv.Itoa(int(s.Index))
data.LinkSectionModelMap[id] = &section.LinkSectionModel{
DeviceModel: face.DeviceModel{
@ -192,6 +569,7 @@ func initGraphicPhysicalSections(physicalSections []*graphicData.Section, data *
SwitchArea: len(s.AxleCountings) > 2,
AxlePoints: make(map[string]face.AxlePointDeviceModeller),
AxleSections: make(map[string]face.AxleSectionModeller),
PortAxlePoints: make(map[string]face.AxlePointDeviceModeller),
}
}
}
@ -232,10 +610,7 @@ func initGraphicSignal(signals []*graphicData.Signal, data *VerifyStructure, gra
// 初始化计算link数据
func initCalcLink(calculateLinks []*graphicData.CalculateLink, verifyStructure *VerifyStructure, graphicDataMap *GraphicInfoMapStructure) {
for _, l := range calculateLinks {
id := strconv.Itoa(int(l.Index))
graphicDataMap.CalcLinkMap[id] = l
}
}
// 构建设备间的关系
@ -258,7 +633,7 @@ func buildDeviceRef(graphicData *GraphicInfoMapStructure, verifyStructure *Verif
// 构建link的关联关系端点间的轨道
func buildLinkDeviceRef(mapData *GraphicInfoMapStructure, verifyStructure *VerifyStructure) {
for _, v := range mapData.LinkMap {
for _, v := range mapData.SectionLinkMap {
link := (verifyStructure.LinkSectionModelMap[strconv.Itoa(int(v.Index))]).(*section.LinkSectionModel)
// 轨道A端端点
linkSimRefBuildCommMethod(v.Common.Id, v.ASimRef, mapData, verifyStructure, func(f face.AxlePointDeviceModeller) {
@ -319,7 +694,7 @@ func linkRefBuildCommMethod(v *graphicData.SectionLink, mapData *GraphicInfoMapS
if r != nil {
switch r.DeviceType {
case graphicData.RelatedRef_SectionLink:
d := mapData.LinkMap[r.Id]
d := mapData.SectionLinkMap[r.Id]
if d != nil {
ls := verifyStructure.LinkSectionModelMap[strconv.Itoa(int(d.Index))]
lr(&ref.LinkRef{LinkSection: ls, Port: face.PortEnum(r.DevicePort)})
@ -346,6 +721,7 @@ func buildTurnoutDeviceRef(verifyStructure *VerifyStructure) {
buildTurnoutCommMethod(s, s.SwitchRefA, face.A)
buildTurnoutCommMethod(s, s.SwitchRefB, face.B)
}
}
func buildTurnoutCommMethod(s *section.LinkSectionModel, linkSwitch *ref.SwitchRef, p face.PortEnum) {
@ -462,11 +838,16 @@ func buildAxlePointDeviceRef(mapData *GraphicInfoMapStructure, verifyStructure *
zap.S().Warnf("id为[%s]的计轴检测点关联的道岔[%s]不存在", id, relatedRef.Id)
}
switchDeviceModel := (verifyStructure.SwitchDeviceModelMap[strconv.Itoa(int(turnout.Index))]).(*device.SwitchDeviceModel)
// 道岔端口对应的计轴
switchDeviceModel.AxlePoints[relatedRef.DevicePort.String()] = axlePointDeviceModel
axlePointDeviceModel.SwitchDevices[switchDeviceModel.Index] = &ref.SwitchRef{
SwitchDevice: switchDeviceModel,
Port: face.PortEnum(relatedRef.DevicePort),
}
case graphicData.RelatedRef_Section:
if relatedRef.Id == "4" {
fmt.Println("")
}
s := mapData.PhysicalSectionMap[relatedRef.Id]
if s == nil {
zap.S().Warnf("id为[%s]的计轴检测点关联的物理区段[%s]不存在", id, relatedRef.Id)
@ -475,6 +856,7 @@ func buildAxlePointDeviceRef(mapData *GraphicInfoMapStructure, verifyStructure *
if physicalSectionModel.SwitchArea {
zap.S().Warnf("id为[%s]的计轴检测点proto数据关联岔区物理区段[%s]不存在", id, relatedRef.Id)
}
physicalSectionModel.PortAxlePoints[relatedRef.DevicePort.String()] = axlePointDeviceModel
switch relatedRef.DevicePort {
case graphicData.RelatedRef_A:
axlePointDeviceModel.LinePhysicalSectionA = physicalSectionModel
@ -496,3 +878,50 @@ func buildPhysicalAxlePointDeviceRef(verifyStructure *VerifyStructure) {
}
}
}
// 将linkPosition转换为计算对象
func convertPositionToCalcPosition(link *device.LinkModel) []*calcLinkPositionStruct {
result := []*calcLinkPositionStruct{}
for _, p := range link.DevicePositions {
s, sok := p.Device.(*device.SwitchDeviceModel)
if sok {
result = append(result, &calcLinkPositionStruct{
index: p.Device.GetIndex(),
deviceType: 2,
position: p,
kilometer: s.KilometerSystems[0],
})
} else {
a, aok := p.Device.(*device.AxlePointDeviceModel)
if aok {
result = append(result, &calcLinkPositionStruct{
index: p.Device.GetIndex(),
deviceType: 1,
position: p,
kilometer: a.KilometerSystem,
})
}
}
}
return result
}
// 判断上下行与link方向是否一直
func convertRunDirectionToUp(ak, bk *graphicData.KilometerSystem, ap, bp *ref.DevicePosition, direction bool) bool {
if bk == nil {
return direction
}
if (ak.Kilometer > bk.Kilometer) == (ap.Offset > bp.Offset) {
return direction
} else {
return !direction
}
}
// 判断是否是否从A端到B端
func convertPointTo(ak, bk *graphicData.KilometerSystem, direction bool) bool {
if bk == nil {
return true == direction
}
return (ak.Kilometer < bk.Kilometer) == direction
}

View File

@ -7,6 +7,8 @@ import (
"strconv"
"sync"
"go.uber.org/zap"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dynamics"
@ -25,14 +27,19 @@ func AddTrainState(simulation *VerifySimulation, status *state.TrainState) {
status.Show = true
//向动力学发送初始化请求
trainIndex, _ := strconv.ParseUint(status.Id, 10, 16)
linkIndex, _ := strconv.ParseUint(status.HeadLinkId, 10, 16)
// 映射link、偏移量、运行方向
linkId, loffset, up, pointTo := QueryMapCalcLinkByDeviceInfo(simulation.MapId, status.HeadDeviceId, status.DevicePort, status.HeadOffset, status.RunDirection)
status.Up = up
status.PointTo = pointTo
httpCode, _, err := dynamics.SendInitTrainReq(&dynamics.InitTrainInfo{
TrainIndex: uint16(trainIndex),
LinkIndex: uint16(linkIndex),
LinkOffset: uint16(status.HeadLinkOffset / 10),
LinkIndex: uint16(linkId),
LinkOffset: uint32(loffset),
Speed: uint16(math.Round(float64(status.Speed * 10))),
Up: status.Up,
})
zap.S().Debugf("添加列车:[%d-%s-%d]", trainIndex, status.HeadLinkId, status.HeadLinkOffset)
zap.S().Debugf("列车初始化:[%d-%d-%d]", trainIndex, linkId, loffset)
if err != nil || httpCode != http.StatusOK {
panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
}
@ -54,6 +61,8 @@ func UpdateTrainState(simulation *VerifySimulation, status *state.TrainState) {
t.Up = status.Up
t.Upslope = status.Upslope
t.RunningUp = status.RunningUp
t.RunDirection = status.RunDirection
t.PointTo = status.PointTo
// 合并其他信息
proto.Merge(t, status)
// 更新全量信息
@ -68,6 +77,13 @@ func RemoveTrainState(simulation *VerifySimulation, id string) {
d, ok := allTrainMap.Load(id)
if ok {
t := d.(*state.TrainState)
trainIndex, _ := strconv.ParseUint(id, 10, 16)
httpCode, _, err := dynamics.SendRemoveTrainReq(&dynamics.InitTrainInfo{
TrainIndex: uint16(trainIndex),
})
if err != nil || httpCode != http.StatusOK {
panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
}
// 从仿真内存中移除列车
t.Show = false
allTrainMap.Store(id, t)

View File

@ -11,7 +11,7 @@ type AxlePointDeviceModel struct {
//计轴检测点基本信息
face.DeviceModel
//端点的公里标,单位为mm
KilometerSystem graphicData.KilometerSystem
KilometerSystem *graphicData.KilometerSystem
//与该计轴点关联的道岔
//key为图形id
SwitchDevices map[string]*ref.SwitchRef

View File

@ -0,0 +1,18 @@
package device
import (
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/ref"
)
type LinkModel struct {
face.DeviceModel
//长度
Length int32
//A端连接的道岔端点
ARelatedSwitchRef ref.SwitchRef
//B端连接的道岔端点
BRelatedSwitchRef ref.SwitchRef
//Link上的设备及位置(包括A、B端的设备)(按offset排序)
DevicePositions []*ref.DevicePosition
}

View File

@ -0,0 +1,12 @@
package device
import (
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
)
// PointModel 线上某一点(本来是想添加坡度和曲线端点,但是他俩数据没有区别,故合为一个通用概念)
type PointModel struct {
face.DeviceModel
Kms []*graphicData.KilometerSystem
}

View File

@ -19,6 +19,8 @@ type SwitchDeviceModel struct {
LinkRefB *ref.LinkRef
//道岔C端连接的link
LinkRefC *ref.LinkRef
// 道岔相连的计轴信息
AxlePoints map[string]*AxlePointDeviceModel
}
// 获取道岔端口关联的轨道

View File

@ -0,0 +1,8 @@
package ref
import "joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
type DevicePosition struct {
Device face.DeviceModeller
Offset int32
}

View File

@ -0,0 +1,13 @@
package section
import "joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
type CurveModel struct {
face.DeviceModel
StartLinkIndex int32
StartLinkOffset int32
EndLinkIndex int32
EndLinkOffset int32
//曲率(半径)mm
Curvature int32
}

View File

@ -14,6 +14,8 @@ type PhysicalSectionModel struct {
//该物理区段中包含的所有计轴区段
//key-图形id
AxleSections map[string]face.AxleSectionModeller
// 端口对应的计轴信息
PortAxlePoints map[string]face.AxlePointDeviceModeller
}
// 添加计轴检测点

View File

@ -0,0 +1,13 @@
package section
import "joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
type SlopeModel struct {
face.DeviceModel
StartLinkIndex int32
StartLinkOffset int32
EndLinkIndex int32
EndLinkOffset int32
//坡度角的三角函数(应该是sin)*1000
DegreeTrig int32
}

@ -1 +1 @@
Subproject commit 9830db4a12bdf1018b89ea5d86fff0832a4a8eb0
Subproject commit ab41f6836f96e8a06ff6edfee202f0bf0c7aecf5

View File

@ -6,7 +6,7 @@ server:
port: 9091
# 动力学端口配置
dynamics:
ip: 192.168.3.94
ip: 192.168.3.222
udpLocalPort: 4000
udpRemotePort: 3000
httpPort: 7800

View File

@ -32,6 +32,7 @@ func newCategory(db *gorm.DB, opts ...gen.DOOption) category {
_category.Config = field.NewString(tableName, "config")
_category.CreatedAt = field.NewTime(tableName, "created_at")
_category.UpdateAt = field.NewTime(tableName, "update_at")
_category.Code = field.NewString(tableName, "code")
_category.fillFieldMap()
@ -47,6 +48,7 @@ type category struct {
Config field.String // 厂家配置
CreatedAt field.Time // 创建时间
UpdateAt field.Time // 修改时间
Code field.String // 编码
fieldMap map[string]field.Expr
}
@ -68,6 +70,7 @@ func (c *category) updateTableName(table string) *category {
c.Config = field.NewString(table, "config")
c.CreatedAt = field.NewTime(table, "created_at")
c.UpdateAt = field.NewTime(table, "update_at")
c.Code = field.NewString(table, "code")
c.fillFieldMap()
@ -84,12 +87,13 @@ func (c *category) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (c *category) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 5)
c.fieldMap = make(map[string]field.Expr, 6)
c.fieldMap["id"] = c.ID
c.fieldMap["name"] = c.Name
c.fieldMap["config"] = c.Config
c.fieldMap["created_at"] = c.CreatedAt
c.fieldMap["update_at"] = c.UpdateAt
c.fieldMap["code"] = c.Code
}
func (c category) clone(db *gorm.DB) category {

View File

@ -33,7 +33,7 @@ func newDrafting(db *gorm.DB, opts ...gen.DOOption) drafting {
_drafting.CreatorID = field.NewInt32(tableName, "creator_id")
_drafting.CreatedAt = field.NewTime(tableName, "created_at")
_drafting.UpdateAt = field.NewTime(tableName, "update_at")
_drafting.Category = field.NewInt32(tableName, "category")
_drafting.Category = field.NewString(tableName, "category")
_drafting.fillFieldMap()
@ -50,7 +50,7 @@ type drafting struct {
CreatorID field.Int32 // 创建人id
CreatedAt field.Time // 创建时间
UpdateAt field.Time // 修改时间
Category field.Int32 // 厂家id
Category field.String // 厂家编码
fieldMap map[string]field.Expr
}
@ -73,7 +73,7 @@ func (d *drafting) updateTableName(table string) *drafting {
d.CreatorID = field.NewInt32(table, "creator_id")
d.CreatedAt = field.NewTime(table, "created_at")
d.UpdateAt = field.NewTime(table, "update_at")
d.Category = field.NewInt32(table, "category")
d.Category = field.NewString(table, "category")
d.fillFieldMap()

View File

@ -32,7 +32,7 @@ func newPublishedGi(db *gorm.DB, opts ...gen.DOOption) publishedGi {
_publishedGi.Proto = field.NewBytes(tableName, "proto")
_publishedGi.UserID = field.NewInt32(tableName, "user_id")
_publishedGi.PublishAt = field.NewTime(tableName, "publish_at")
_publishedGi.Category = field.NewInt32(tableName, "category")
_publishedGi.Category = field.NewString(tableName, "category")
_publishedGi.Note = field.NewString(tableName, "note")
_publishedGi.Status = field.NewInt32(tableName, "status")
@ -50,7 +50,7 @@ type publishedGi struct {
Proto field.Bytes // 图形界面数据
UserID field.Int32 // 发布用户id
PublishAt field.Time // 发布时间
Category field.Int32 // 厂家信息
Category field.String // 厂家信息
Note field.String // 发布描述
Status field.Int32 // 显示状态
@ -74,7 +74,7 @@ func (p *publishedGi) updateTableName(table string) *publishedGi {
p.Proto = field.NewBytes(table, "proto")
p.UserID = field.NewInt32(table, "user_id")
p.PublishAt = field.NewTime(table, "publish_at")
p.Category = field.NewInt32(table, "category")
p.Category = field.NewString(table, "category")
p.Note = field.NewString(table, "note")
p.Status = field.NewInt32(table, "status")

View File

@ -17,6 +17,7 @@ type Category struct {
Config string `gorm:"column:config;comment:厂家配置" json:"config"` // 厂家配置
CreatedAt time.Time `gorm:"column:created_at;not null;comment:创建时间" json:"created_at"` // 创建时间
UpdateAt time.Time `gorm:"column:update_at;comment:修改时间" json:"update_at"` // 修改时间
Code string `gorm:"column:code;comment:编码" json:"code"` // 编码
}
// TableName Category's table name

View File

@ -18,7 +18,7 @@ type Drafting struct {
CreatorID int32 `gorm:"column:creator_id;not null;comment:创建人id" json:"creator_id"` // 创建人id
CreatedAt time.Time `gorm:"column:created_at;not null;comment:创建时间" json:"created_at"` // 创建时间
UpdateAt time.Time `gorm:"column:update_at;comment:修改时间" json:"update_at"` // 修改时间
Category int32 `gorm:"column:category;comment:厂家id" json:"category"` // 厂家id
Category string `gorm:"column:category;comment:厂家编码" json:"category"` // 厂家编码
}
// TableName Drafting's table name

View File

@ -17,7 +17,7 @@ type PublishedGi struct {
Proto []byte `gorm:"column:proto;not null;comment:图形界面数据" json:"proto"` // 图形界面数据
UserID int32 `gorm:"column:user_id;not null;comment:发布用户id" json:"user_id"` // 发布用户id
PublishAt time.Time `gorm:"column:publish_at;not null;comment:发布时间" json:"publish_at"` // 发布时间
Category int32 `gorm:"column:category;comment:厂家信息" json:"category"` // 厂家信息
Category string `gorm:"column:category;comment:厂家信息" json:"category"` // 厂家信息
Note string `gorm:"column:note;comment:发布描述" json:"note"` // 发布描述
Status int32 `gorm:"column:status;default:1;comment:显示状态" json:"status"` // 显示状态
}

View File

@ -7,6 +7,7 @@ type PageCategoryReqDto struct {
type CategoryDto struct {
Id int `json:"id" form:"id"`
Code string `json:"code" form:"code"`
Name string `json:"name" form:"name"`
Config string `json:"config" form:"config"`
}

View File

@ -8,7 +8,7 @@ type PageDraftingReqDto struct {
type DraftingDto struct {
Id int `json:"id" form:"id"`
Name string `json:"name" form:"name"`
Category int32 `json:"category" form:"category"`
Category string `json:"category" form:"category"`
Proto []byte `json:"proto" from:"proto"`
}

View File

@ -21,11 +21,17 @@ type AddTrainReqDto struct {
//仿真id
SimulationId string `json:"simulationId" form:"simulationId"`
//列车方向,true-上行false-下行
Up bool `json:"up" form:"up"`
RunDirection bool `json:"up" form:"up"`
//车头所在link的索引
HeadLinkId string `json:"headLinkId" form:"headLinkId"`
//车头所在link内的偏移量单位为mm
HeadLinkOffset int64 `json:"headLinkOffset" form:"headLinkOffset"`
//物理区段、道岔ID
Id string `json:"id" form:"id"`
//道岔端口
DevicePort string `json:"devicePort" form:"devicePort"`
//车头所在link内的偏移量单位为mm
HeadOffset int64 `json:"headOffset" form:"headOffset"`
}
// 为仿真添加测试车请求

View File

@ -4,8 +4,10 @@ import (
"bytes"
"encoding/json"
"fmt"
"joylink.club/bj-rtsts-server/config"
"net/http"
"time"
"joylink.club/bj-rtsts-server/config"
)
func SendInitTrainReq(info *InitTrainInfo) (int, *[]byte, error) {
@ -13,7 +15,32 @@ func SendInitTrainReq(info *InitTrainInfo) (int, *[]byte, error) {
uri := "/api/aerodynamics/init/train/"
url := baseUrl + uri
data, _ := json.Marshal(info)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
client := http.Client{
Timeout: time.Second * 5,
}
resp, err := client.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
s := err.Error()
println(s)
return 0, nil, err
}
var buf []byte
_, err = resp.Body.Read(buf)
if err != nil {
return resp.StatusCode, nil, err
}
return resp.StatusCode, &buf, resp.Body.Close()
}
func SendRemoveTrainReq(info *InitTrainInfo) (int, *[]byte, error) {
baseUrl := getUrlBase()
uri := "/api/aerodynamics/remove/train/"
url := baseUrl + uri
data, _ := json.Marshal(info)
client := http.Client{
Timeout: time.Second * 5,
}
resp, err := client.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
s := err.Error()
println(s)
@ -48,7 +75,7 @@ func SendSimulationStartReq(base *LineBaseInfo) (int, *[]byte, error) {
func SendSimulationEndReq() (int, *[]byte, error) {
baseUrl := getUrlBase()
uri := "/api/end"
uri := "/api/end/"
url := baseUrl + uri
resp, err := http.Post(url, "application/json", nil)
if err != nil {

View File

@ -3,7 +3,7 @@ package dynamics
type InitTrainInfo struct {
TrainIndex uint16 `json:"trainIndex"`
LinkIndex uint16 `json:"linkIndex"`
LinkOffset uint16 `json:"linkOffset"`
LinkOffset uint32 `json:"linkOffset"`
//单位0.1km/h
Speed uint16 `json:"speed"`
Up bool `json:"up"`
@ -11,9 +11,9 @@ type InitTrainInfo struct {
// LineBaseInfo 线路基础信息,提供给动力学作为计算依据
type LineBaseInfo struct {
LinkList []Link `json:"linkList"`
SlopeList []Slope `json:"slopeList"`
CurveList []Curve `json:"curveList"`
LinkList []*Link `json:"linkList"`
SlopeList []*Slope `json:"slopeList"`
CurveList []*Curve `json:"curveList"`
}
type Link struct {

View File

@ -3,6 +3,7 @@ package dynamics
import (
"container/list"
"encoding/binary"
"errors"
"fmt"
"github.com/panjf2000/gnet/v2"
"go.uber.org/zap"
@ -14,43 +15,72 @@ import (
)
func init() {
runSendTurnoutStateTask()
}
var (
m sync.Map
)
type TurnoutInfoFunc func() []*TurnoutInfo
func runSendTurnoutStateTask() {
go func() {
tick := time.Tick(50 * time.Millisecond)
for range tick {
m.Range(func(key, value any) bool {
slice := value.(TurnoutInfoFunc)()
for _, turnoutInfo := range slice {
err := SendTurnoutInfo(turnoutInfo)
if err != nil {
zap.S().Error(err)
for true {
info := <-trainInfoChan
for e := handlerList.Front(); e != nil; e = e.Next() {
func() {
defer func() {
r := recover()
if r != nil {
zap.S().Errorf("列车信息处理函数报错")
}
}()
handler := e.Value.(TrainInfoHandler)
handler(info)
}()
}
return true
})
}
}()
}
func AddTurnoutInfoSource(simId string, tiFunc TurnoutInfoFunc) {
m.Store(simId, tiFunc)
type TurnoutInfoFunc func() []*TurnoutInfo
var (
running bool
mutex sync.Mutex
turnoutInfoFunc TurnoutInfoFunc
//道岔消息生命信号
turnoutLifeSignal uint16
//列车消息生命信号
trainLifeSignal uint16
//列车生命信号是否初始化
trainLifeSignalInit bool
//用于处理生命信号循环使用产生的各种特殊处理
limit uint16 = 10000
//列车消息队列
trainInfoChan chan *TrainInfo = make(chan *TrainInfo)
)
func Run(tiFunc TurnoutInfoFunc) error {
mutex.Lock()
defer mutex.Unlock()
trainLifeSignalInit = false
return runSendTurnoutStateTask(tiFunc)
}
func RemoveTurnoutInfoSource(simId string) {
m.Delete(simId)
func Stop() {
mutex.Lock()
defer mutex.Unlock()
turnoutInfoFunc = nil
}
// SendTurnoutInfo 发送道岔信息
func SendTurnoutInfo(info *TurnoutInfo) error {
var handlerList list.List
type TrainInfoHandler func(info *TrainInfo)
func RegisterTrainInfoHandler(handler TrainInfoHandler) {
handlerList.PushBack(handler)
}
func RunUdpServer() {
server := &udpServer{addr: fmt.Sprintf("udp://:%d", config.Config.Dynamics.UdpLocalPort), multicore: false}
err := gnet.Run(server, server.addr, gnet.WithMulticore(server.multicore))
zap.L().Fatal("udp服务启动失败", zap.Error(err))
}
// sendTurnoutInfo 发送道岔信息
func sendTurnoutInfo(info *TurnoutInfo) error {
defer func() {
if r := recover(); r != nil {
zap.S().Error("发送道岔信息失败", r)
@ -70,6 +100,7 @@ func SendTurnoutInfo(info *TurnoutInfo) error {
}
}(conn)
var data []byte
data = binary.BigEndian.AppendUint16(data, info.lifeSignal)
data = binary.BigEndian.AppendUint16(data, info.Code)
var b byte
if info.NPosition {
@ -105,12 +136,32 @@ func (server *udpServer) OnBoot(eng gnet.Engine) gnet.Action {
func (server *udpServer) OnTraffic(c gnet.Conn) gnet.Action {
defer func() {
if r := recover(); r != nil {
zap.S().Error("udp服务数据解析异常", r)
zap.L().Error("udp服务数据解析异常", zap.Any("panic", r))
}
}()
buf, _ := c.Next(-1)
trainInfo := TrainInfo{}
trainInfo.LifeSignal = binary.BigEndian.Uint16(buf[0:2])
if !trainLifeSignalInit {
trainLifeSignalInit = true
trainLifeSignal = trainInfo.LifeSignal
} else if trainLifeSignal < limit {
if trainInfo.LifeSignal < trainLifeSignal || trainInfo.LifeSignal > trainLifeSignal-limit {
zap.S().Debugf("丢弃列车信息[%d-%d]", trainInfo.LifeSignal, trainLifeSignal)
return gnet.None
}
} else if trainLifeSignal < math.MaxUint16-10000 {
if trainInfo.LifeSignal < trainLifeSignal {
zap.S().Debugf("丢弃列车信息[%d-%d]", trainInfo.LifeSignal, trainLifeSignal)
return gnet.None
}
} else {
if trainInfo.LifeSignal < trainLifeSignal && trainInfo.LifeSignal > trainLifeSignal+10000 {
zap.S().Debugf("丢弃列车信息[%d-%d]", trainInfo.LifeSignal, trainLifeSignal)
return gnet.None
}
}
trainLifeSignal = trainInfo.LifeSignal
trainInfo.Number = buf[2]
trainInfo.Len = binary.BigEndian.Uint16(buf[3:5])
trainInfo.Link = buf[5]
@ -131,24 +182,40 @@ func (server *udpServer) OnTraffic(c gnet.Conn) gnet.Action {
trainInfo.HeadRadarSpeed = math.Float32frombits(binary.BigEndian.Uint32(buf[50:54]))
trainInfo.TailRadarSpeed = math.Float32frombits(binary.BigEndian.Uint32(buf[54:58]))
for e := handlerList.Front(); e != nil; e = e.Next() {
handler := e.Value.(TrainInfoHandler)
handler(&trainInfo)
}
trainInfoChan <- &trainInfo
return gnet.None
}
var handlerList list.List
type TrainInfoHandler func(info *TrainInfo)
func RegisterTrainInfoHandler(handler TrainInfoHandler) {
handlerList.PushBack(handler)
func runSendTurnoutStateTask(tiFunc TurnoutInfoFunc) error {
if running {
return nil
}
func RunUdpServer() {
server := &udpServer{addr: fmt.Sprintf("udp://:%d", config.Config.Dynamics.UdpLocalPort), multicore: false}
err := gnet.Run(server, server.addr, gnet.WithMulticore(server.multicore))
zap.L().Fatal("udp服务启动失败", zap.Error(err))
if tiFunc == nil {
return errors.New("tiFunc不能为空")
}
turnoutInfoFunc = tiFunc
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
tick := time.Tick(50 * time.Millisecond)
for range tick {
if turnoutInfoFunc == nil {
continue
}
slice := turnoutInfoFunc()
for _, turnoutInfo := range slice {
turnoutInfo.lifeSignal = turnoutLifeSignal
err := sendTurnoutInfo(turnoutInfo)
if err != nil {
zap.S().Error(err)
}
}
turnoutLifeSignal++
}
}()
return nil
}

View File

@ -1,6 +1,7 @@
package dynamics
type TurnoutInfo struct {
lifeSignal uint16
Code uint16
NPosition bool
RPosition bool
@ -21,7 +22,7 @@ type TrainInfo struct {
Slope uint16
//列车所在位置坡度走势(上/下坡)
UpSlope bool
//列车当前运行方向(上/下行
//列车当前运行方向(偏移量增大/减小方向
Up bool
//实际运行阻力N
TotalResistance uint32

View File

@ -29,7 +29,7 @@ func TestSendTurnoutInfo(t *testing.T) {
tick := time.Tick(50 * time.Millisecond)
for range tick {
for i := 1; i <= 9; i++ {
SendTurnoutInfo(&TurnoutInfo{
sendTurnoutInfo(&TurnoutInfo{
Code: uint16(i),
NPosition: true,
RPosition: false,

View File

@ -16,7 +16,7 @@ func PageCategoryQuery(query *dto.PageCategoryReqDto) (*dto.PageDto, error) {
if query.Name != "" {
dq = dq.Where(d.Name.Like(fmt.Sprintf("%%%s%%", query.Name)))
}
records, total, err := dq.Debug().Select(d.ID, d.Name, d.UpdateAt, d.CreatedAt).FindByPage(query.Offset(), query.Size)
records, total, err := dq.Debug().Select(d.ID, d.Code, d.Name, d.UpdateAt, d.CreatedAt).FindByPage(query.Offset(), query.Size)
if err != nil {
panic(err)
}
@ -30,7 +30,7 @@ func ListCategoryQuery(query *dto.PageCategoryReqDto) ([]*model.Category, error)
if query.Name != "" {
dq = dq.Where(d.Name.Like(fmt.Sprintf("%%%s%%", query.Name)))
}
records, err := dq.Debug().Select(d.ID, d.Name, d.UpdateAt, d.CreatedAt).Find()
records, err := dq.Debug().Select(d.ID, d.Code, d.Name, d.UpdateAt, d.CreatedAt).Find()
if err != nil {
panic(err)
}
@ -39,11 +39,12 @@ func ListCategoryQuery(query *dto.PageCategoryReqDto) ([]*model.Category, error)
// 创建草稿
func CreateCategory(dto *dto.CategoryDto) (*model.Category, error) {
if err := checkCategoryInfo(dto.Name); err != nil {
if err := checkCategoryInfo(dto.Name, dto.Code, 0); err != nil {
panic(err)
}
d := model.Category{
Name: dto.Name,
Code: dto.Code,
Config: dto.Config,
CreatedAt: time.Now(),
UpdateAt: time.Now(),
@ -64,11 +65,17 @@ func QueryCategory(id int32) *model.Category {
}
func UpdateCategory(id int32, dto *dto.CategoryDto) bool {
if err := checkCategoryInfo(dto.Name, dto.Code, id); err != nil {
panic(err)
}
findOldQuery := dbquery.Category
oldD, err := findOldQuery.Where(findOldQuery.ID.Eq(id)).Debug().First()
if oldD == nil || err != nil {
panic(err)
}
if dto.Code != "" {
oldD.Code = dto.Code
}
if dto.Config != "" {
oldD.Config = dto.Config
}
@ -87,14 +94,29 @@ func DeleteCategoryById(id int) {
_, _ = dbquery.Category.Debug().Where(dbquery.Category.ID.Eq(int32(id))).Delete()
}
func checkCategoryInfo(name string) error {
func checkCategoryInfo(name string, code string, id int32) error {
findNameQuery := dbquery.Category
count, err := findNameQuery.Where(findNameQuery.Name.Eq(name)).Debug().Count()
w := findNameQuery.Where()
if id != 0 {
w = w.Where(findNameQuery.ID.Eq(id))
}
if name != "" {
count, err := w.Where(findNameQuery.Name.Eq(name)).Debug().Count()
if err != nil {
panic(err)
}
if count > 0 {
panic("名称已存在")
}
return err
}
if code != "" {
count, err := w.Where(findNameQuery.Code.Eq(code)).Debug().Count()
if err != nil {
panic(err)
}
if count > 0 {
panic("编码已存在")
}
}
return nil
}