diff --git a/examples/rtss-cg/linux_amd64_make.bat b/examples/rtss-cg/linux_amd64_make.bat new file mode 100644 index 0000000..fbf0f11 --- /dev/null +++ b/examples/rtss-cg/linux_amd64_make.bat @@ -0,0 +1,9 @@ +@echo off + +set CGO_ENABLED=0 +set GOARCH=amd64 +set GOOS=linux +set APP_NAME=%GOOS%_%GOARCH%_app +echo complie ... +go build -o %APP_NAME% main.go +echo complie output %APP_NAME% \ No newline at end of file diff --git a/examples/rtss-cg/main.go b/examples/rtss-cg/main.go index 17916c4..8b7d589 100644 --- a/examples/rtss-cg/main.go +++ b/examples/rtss-cg/main.go @@ -1,7 +1,6 @@ package main import ( - "log" "time" "github.com/yohamta/donburi/filter" @@ -35,34 +34,31 @@ import ( */ // // -func init() { - log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate) -} - -// 1 world 须增加attach , 绑定与该world相关的信息 -// 2 事件的订阅、发布、处理是独立调用执行的,事件处理可以集中处理也可以只处理某类事件 func main() { // - simWorld := ecs.NewWorld(400) + simWorld := ecs.NewWorld(300) // initMemoryModel(simWorld) //道岔 initSwitchState(simWorld) //轨道 initLinkState(simWorld) - //添加列车 - initTrainState(simWorld, "train1", iwayside.LinkLocation{LinkId: "link4", LinkOffset: 3000 * 100 * 10}, false) + //物理区段 + initPhsicalSectionState(simWorld) // simWorld.AddSystem(system.NewSwitchSystem()) simWorld.AddSystem(system.NewTrainSystem()) - simWorld.AddSystem(system.NewCiSystem()) + //simWorld.AddSystem(system.NewCiSystem()) + simWorld.AddSystem(system.NewSectionSystem()) // simWorld.StartUp() // - time.Sleep(2 * time.Second) - // operateSwitch(simWorld, "dc1") operateSwitch(simWorld, "dc2") + time.Sleep(10 * time.Second) + //添加列车 + initTrainState(simWorld, "train1", iwayside.LinkLocation{LinkId: "link4", LinkOffset: 3000 * 100 * 10}, false) + initTrainState(simWorld, "train2", iwayside.LinkLocation{LinkId: "link4", LinkOffset: 1000 * 100 * 10}, false) time.Sleep(200 * time.Second) } @@ -108,6 +104,16 @@ func initLinkState(world ecs.World) { } } +// 初始化物理区段状态 +func initPhsicalSectionState(world ecs.World) { + simMemory := simulation.GetMemoryModel(world) + for _, phSecModel := range simMemory.PhysicalSections { + sectionState := &state.PhysicalSectionState{Id: phSecModel.GetId(), Occupied: false} + sectionEntry := world.Create(simulation.ComPhsicalSectionState) + simulation.ComPhsicalSectionState.Set(sectionEntry, sectionState) + } +} + // 添加列车并初始化 func initTrainState(world ecs.World, trainId string, linkLocation iwayside.LinkLocation, up bool) { train := &state.TrainState{Id: trainId, LinkId: linkLocation.LinkId, LinkOffset: linkLocation.LinkOffset, Up: up} diff --git a/examples/rtss-cg/mwayside/link_model.go b/examples/rtss-cg/mwayside/link_model.go index 777b16a..8836c7f 100644 --- a/examples/rtss-cg/mwayside/link_model.go +++ b/examples/rtss-cg/mwayside/link_model.go @@ -1,5 +1,7 @@ package mwayside +import "joylink.club/rtss/iwayside" + //长link只与道岔相连 type LinkModel struct { //轨道基本信息 @@ -11,3 +13,15 @@ type LinkModel struct { //轨道B端连接的道岔 PortB *SwitchRef } + +//与该轨道连接的所有道岔 +func (me *LinkModel) FindSwitchModels() []iwayside.ISwitchModel { + var dcs []iwayside.ISwitchModel + if nil != me.PortA { + dcs = append(dcs, me.PortA.Switch) + } + if nil != me.PortB { + dcs = append(dcs, me.PortB.Switch) + } + return dcs +} diff --git a/examples/rtss-cg/mwayside/physical_section_model.go b/examples/rtss-cg/mwayside/physical_section_model.go index 556210a..51b7d84 100644 --- a/examples/rtss-cg/mwayside/physical_section_model.go +++ b/examples/rtss-cg/mwayside/physical_section_model.go @@ -1,8 +1,10 @@ package mwayside -import "joylink.club/rtss/iwayside" +import ( + "joylink.club/rtss/iwayside" +) -//物理区段 +// 物理区段 type PhysicalSectionModel struct { DeviceModel //true-线性物理区段;false-岔区物理区段 @@ -15,7 +17,7 @@ type PhysicalSectionModel struct { AreaAxlePoints []iwayside.IAxlePointModel } -//创建线性物理区段模型 +// 创建线性物理区段模型 func NewLinePhysicalSectionModel(id string, axlePointPortA iwayside.IAxlePointModel, axlePointPortB iwayside.IAxlePointModel) *PhysicalSectionModel { return &PhysicalSectionModel{ DeviceModel: DeviceModel{Id: id, Type: iwayside.PhysicalSection}, @@ -25,7 +27,7 @@ func NewLinePhysicalSectionModel(id string, axlePointPortA iwayside.IAxlePointMo } } -//创建岔区物理区段模型 +// 创建岔区物理区段模型 func NewAreaPhysicalSectionModel(id string, axlePointPorts ...iwayside.IAxlePointModel) *PhysicalSectionModel { return &PhysicalSectionModel{ DeviceModel: DeviceModel{Id: id, Type: iwayside.PhysicalSection}, diff --git a/examples/rtss-cg/mwayside/switch_model.go b/examples/rtss-cg/mwayside/switch_model.go index d9c8e5f..c2d08f8 100644 --- a/examples/rtss-cg/mwayside/switch_model.go +++ b/examples/rtss-cg/mwayside/switch_model.go @@ -1,5 +1,7 @@ package mwayside +import "joylink.club/rtss/iwayside" + type SwitchModel struct { //道岔基本信息 DeviceModel @@ -12,3 +14,17 @@ type SwitchModel struct { //道岔公里标,单位mm KilometerSign int64 } + +// 判端轨道是否与该道岔连接 +func (me *SwitchModel) IsLink(link iwayside.ILinkModel) bool { + if nil != me.PortA && link.GetId() == me.PortA.Link.GetId() { + return true + } + if nil != me.PortB && link.GetId() == me.PortB.Link.GetId() { + return true + } + if nil != me.PortC && link.GetId() == me.PortC.Link.GetId() { + return true + } + return false +} diff --git a/examples/rtss-cg/simulation/ecs_components.go b/examples/rtss-cg/simulation/ecs_components.go index 7c3df84..044c829 100644 --- a/examples/rtss-cg/simulation/ecs_components.go +++ b/examples/rtss-cg/simulation/ecs_components.go @@ -12,6 +12,9 @@ var ComSwitchOperating = ecs.NewComponentType[state.SwitchOperating]() // 轨道状态组件 var ComLinkState = ecs.NewComponentType[state.LinkState]() +// 物理区段状态 +var ComPhsicalSectionState = ecs.NewComponentType[state.PhysicalSectionState]() + // 列车状态组件 var ComTrainState = ecs.NewComponentType[state.TrainState]() diff --git a/examples/rtss-cg/simulation/sim_memory.go b/examples/rtss-cg/simulation/sim_memory.go index bfb5ffa..1709914 100644 --- a/examples/rtss-cg/simulation/sim_memory.go +++ b/examples/rtss-cg/simulation/sim_memory.go @@ -5,6 +5,7 @@ import ( "github.com/yohamta/donburi/filter" "joylink.club/ecs" "joylink.club/rtss/iwayside" + "joylink.club/rtss/mwayside" ) type SimMemory struct { @@ -29,3 +30,13 @@ func GetMemoryModel(world ecs.World) *SimMemory { } return nil } + +// 将列车轨道位置偏移转换为公里标,道岔处用投影近似 +func (me *SimMemory) LinkOffsetToKilometerSign(linkId string, linkOffset int64) int64 { + link := me.Links[linkId].(*mwayside.LinkModel) + if nil != link.PortA { + return link.PortA.Switch.(*mwayside.SwitchModel).KilometerSign + linkOffset + } else { + return link.PortB.Switch.(*mwayside.SwitchModel).KilometerSign - linkOffset + } +} diff --git a/examples/rtss-cg/state/section_state.go b/examples/rtss-cg/state/section_state.go new file mode 100644 index 0000000..105c8d1 --- /dev/null +++ b/examples/rtss-cg/state/section_state.go @@ -0,0 +1,9 @@ +package state + +//物理区段状态 +type PhysicalSectionState struct { + //区段id + Id string + //是否有车占用 + Occupied bool +} diff --git a/examples/rtss-cg/system/section_system.go b/examples/rtss-cg/system/section_system.go new file mode 100644 index 0000000..fb60097 --- /dev/null +++ b/examples/rtss-cg/system/section_system.go @@ -0,0 +1,132 @@ +package system + +import ( + "fmt" + "strings" + + "github.com/yohamta/donburi/filter" + "joylink.club/ecs" + "joylink.club/rtss/iwayside" + "joylink.club/rtss/mwayside" + "joylink.club/rtss/simulation" + "joylink.club/rtss/state" +) + +// 物理区段状态检测 +type SectionSystem struct { + //列车查询 + trainQuery *ecs.Query + //物理区段查询 + sectionQuery *ecs.Query +} + +func NewSectionSystem() *SectionSystem { + return &SectionSystem{ + trainQuery: ecs.NewQuery(filter.Contains(simulation.ComTrainState)), + sectionQuery: ecs.NewQuery(filter.Contains(simulation.ComPhsicalSectionState)), + } +} +func (me *SectionSystem) Update(w ecs.World) { + memory := simulation.GetMemoryModel(w) + //收集轨道占用点 + var standPoints []*standingPoint + me.trainQuery.Each(w, func(e *ecs.Entry) { + train := simulation.ComTrainState.Get(e) + standPoints = append(standPoints, &standingPoint{link: memory.Links[train.LinkId].(*mwayside.LinkModel), offset: train.LinkOffset}) + }) + //物理区段状态 + me.sectionQuery.Each(w, func(e *ecs.Entry) { + sectionState := simulation.ComPhsicalSectionState.Get(e) + sectionState.Occupied = checkOccupy(memory, standPoints, sectionState) + }) + // + sb := &strings.Builder{} + me.sectionQuery.Each(w, func(e *ecs.Entry) { + sectionState := simulation.ComPhsicalSectionState.Get(e) + sb.WriteString(fmt.Sprintf("区段[%s]占用[%t] ||", sectionState.Id, sectionState.Occupied)) + }) + fmt.Println("==>>", sb.String()) +} + +// 判断物理区段是否有列车占用 +func checkOccupy(memory *simulation.SimMemory, standPoints []*standingPoint, sectionState *state.PhysicalSectionState) bool { + occupied := false + // + sectionModel := memory.PhysicalSections[sectionState.Id].(*mwayside.PhysicalSectionModel) + for _, standPoint := range standPoints { + if occupied = containsPoint(sectionModel, standPoint); occupied { + break + } + } + // + return occupied +} +func containsPoint(sectionModel *mwayside.PhysicalSectionModel, point *standingPoint) bool { + + if sectionModel.Line { + if sectionModel.AxlePointPortA.(*mwayside.AxlePointModel).Link.GetId() != point.link.GetId() || sectionModel.AxlePointPortB.(*mwayside.AxlePointModel).Link.GetId() != point.link.GetId() { + return false + } + offsetKilometerSign := linkOffsetToKilometerSign(point.link, point.offset) + return offsetKilometerSign > sectionModel.AxlePointPortA.(*mwayside.AxlePointModel).KilometerSign && offsetKilometerSign < sectionModel.AxlePointPortB.(*mwayside.AxlePointModel).KilometerSign + } else { //岔区物理区段 + //物理区段中的道岔 + sectionDc := findPhsicalSectionSwitches(sectionModel).(*mwayside.SwitchModel) + sectionDcKilometerSign := sectionDc.KilometerSign + //占用点公里标 + standKilometerSign := linkOffsetToKilometerSign(point.link, point.offset) + for _, axle := range sectionModel.AreaAxlePoints { + if sectionDc.IsLink(axle.(*mwayside.AxlePointModel).Link) { + axleKilometerSign := axle.(*mwayside.AxlePointModel).KilometerSign + if axleKilometerSign < sectionDcKilometerSign { + return standKilometerSign > axleKilometerSign && standKilometerSign < sectionDcKilometerSign + } else { + return standKilometerSign > sectionDcKilometerSign && standKilometerSign < axleKilometerSign + } + } + } + return false + } +} + +// 轨道偏移转换为公里标 +func linkOffsetToKilometerSign(link *mwayside.LinkModel, offset int64) int64 { + var rate float64 = float64(offset) / float64(link.Len) + if nil != link.PortA && nil != link.PortB { + portASwitch := link.PortA.Switch.(*mwayside.SwitchModel) + portBSwitch := link.PortB.Switch.(*mwayside.SwitchModel) + return portASwitch.KilometerSign + int64(float64(portBSwitch.KilometerSign-portASwitch.KilometerSign)*rate) + } else if nil != link.PortA && nil == link.PortB { + portASwitch := link.PortA.Switch.(*mwayside.SwitchModel) + return portASwitch.KilometerSign + offset + } else { //nil == link.PortA && nil != link.PortB + portBSwitch := link.PortB.Switch.(*mwayside.SwitchModel) + return portBSwitch.KilometerSign - link.Len + offset + } + +} + +// 被占用的轨道点定义 +type standingPoint struct { + link *mwayside.LinkModel + offset int64 +} + +// 岔区物理区段,则返回计轴集合框定的道岔 +func findPhsicalSectionSwitches(me *mwayside.PhysicalSectionModel) iwayside.ISwitchModel { + if len(me.AreaAxlePoints) == 0 { + return nil + } + dcMap := make(map[string]iwayside.ISwitchModel) + for _, axle := range me.AreaAxlePoints { + linkDcs := axle.(*mwayside.AxlePointModel).Link.(*mwayside.LinkModel).FindSwitchModels() + for _, linkDc := range linkDcs { + if _, ok := dcMap[linkDc.GetId()]; !ok { + dcMap[linkDc.GetId()] = linkDc + } else { + return linkDc + } + } + } + return nil +} diff --git a/examples/rtss-cg/system/switch_system.go b/examples/rtss-cg/system/switch_system.go index ed6b747..5dbfde0 100644 --- a/examples/rtss-cg/system/switch_system.go +++ b/examples/rtss-cg/system/switch_system.go @@ -6,6 +6,7 @@ import ( "github.com/yohamta/donburi/filter" "joylink.club/ecs" + "joylink.club/rtss/mwayside" "joylink.club/rtss/simulation" ) @@ -36,3 +37,16 @@ func (me *SwitchSystem) Update(w ecs.World) { func NewSwitchSystem() *SwitchSystem { return &SwitchSystem{ComQuery: ecs.NewQuery(filter.Contains(simulation.ComSwitchOperating))} } + +// 判断点是否在该物理区段内 +func ContainsPoint(me *mwayside.PhysicalSectionModel, linkId string, kilometerSign int64) bool { + if me.AxlePointPortA.(*mwayside.AxlePointModel).Link.GetId() != linkId || me.AxlePointPortB.(*mwayside.AxlePointModel).Link.GetId() != linkId { + return false + } + if me.Line { + return me.AxlePointPortA.(*mwayside.AxlePointModel).KilometerSign < kilometerSign && me.AxlePointPortB.(*mwayside.AxlePointModel).KilometerSign > kilometerSign + } else { + + } + return true +} diff --git a/examples/rtss-cg/system/train_system.go b/examples/rtss-cg/system/train_system.go index c5d2300..d0a642a 100644 --- a/examples/rtss-cg/system/train_system.go +++ b/examples/rtss-cg/system/train_system.go @@ -23,6 +23,7 @@ func (me *TrainSystem) Update(w ecs.World) { fmt.Println("==>>列车 id = ", train.Id, " linkId = ", train.LinkId, " offset = ", train.LinkOffset, " up = ", train.Up) curLink := findTrainLinkModel(w, train.LinkId) var offset int64 = train.LinkOffset + func() int64 { + //列车一个循环移动1m if train.Up { return 20 * 1000 } else {