ecs 测试

This commit is contained in:
xzb 2023-08-10 18:11:26 +08:00
parent b2a4bdb779
commit 73b1bfcb96
11 changed files with 234 additions and 17 deletions

View File

@ -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%

View File

@ -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}

View File

@ -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
}

View File

@ -1,6 +1,8 @@
package mwayside
import "joylink.club/rtss/iwayside"
import (
"joylink.club/rtss/iwayside"
)
// 物理区段
type PhysicalSectionModel struct {

View File

@ -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
}

View File

@ -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]()

View File

@ -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
}
}

View File

@ -0,0 +1,9 @@
package state
//物理区段状态
type PhysicalSectionState struct {
//区段id
Id string
//是否有车占用
Occupied bool
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {