计轴rssp 集成
This commit is contained in:
parent
5667b3fcd1
commit
cf648670bf
@ -4,16 +4,19 @@ import "joylink.club/ecs"
|
||||
|
||||
// TrainPositionInfo 列车当前位置信息
|
||||
type TrainPositionInfo struct {
|
||||
//列车所占的物理区段
|
||||
SectionIds []string
|
||||
//列车长度 mm
|
||||
Len uint32
|
||||
//列车所在轨道link
|
||||
Link uint8
|
||||
//列车所在link偏移量(mm)
|
||||
LinkOffset uint32
|
||||
//列车当前运行方向(偏移量增大/减小方向)
|
||||
//列车头当前运行方向(true偏移量增大/false减小方向)
|
||||
//link 由a->b偏移量增大
|
||||
Up bool
|
||||
//列车长度 mm
|
||||
Len int64
|
||||
//列车所在轨道link
|
||||
HeadLink string
|
||||
//列车所在link偏移量(mm)
|
||||
HeadLinkOffset int64
|
||||
//列车所在轨道link
|
||||
TailLink string
|
||||
//列车所在link偏移量(mm)
|
||||
TailLinkOffset int64
|
||||
}
|
||||
|
||||
var (
|
||||
|
33
fi/train.go
33
fi/train.go
@ -2,7 +2,6 @@ package fi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"joylink.club/ecs"
|
||||
"joylink.club/rtsssimulation/component"
|
||||
"joylink.club/rtsssimulation/entity"
|
||||
@ -35,26 +34,24 @@ func RemoveTrainFromWorld(w ecs.World, trainId string) error {
|
||||
return result.Err
|
||||
}
|
||||
|
||||
// UpdateTrainFromDynamics 更新列车所在的物理区段
|
||||
func UpdateTrainFromDynamics(w ecs.World, trainId string, sectionIds []string) error {
|
||||
result := <-ecs.Request[ecs.EmptyType](w, func() ecs.Result[ecs.EmptyType] {
|
||||
wd := entity.GetWorldData(w)
|
||||
te, find := wd.EntityMap[trainId]
|
||||
if find {
|
||||
tp := component.TrainPositionInfoType.Get(te)
|
||||
tp.SectionIds = sectionIds
|
||||
return ecs.NewOkEmptyResult()
|
||||
} else {
|
||||
return ecs.NewErrResult(fmt.Errorf("列车[%s]实体不存在", trainId))
|
||||
}
|
||||
})
|
||||
return result.Err
|
||||
}
|
||||
|
||||
// UpdateTrainPositionFromDynamics 更新列车所在的物理区段
|
||||
func UpdateTrainPositionFromDynamics(w ecs.World, tpi TrainPositionInfo) error {
|
||||
result := <-ecs.Request[ecs.EmptyType](w, func() ecs.Result[ecs.EmptyType] {
|
||||
return ecs.NewOkEmptyResult()
|
||||
wd := entity.GetWorldData(w)
|
||||
te, find := wd.EntityMap[tpi.TrainId]
|
||||
if find {
|
||||
train := component.TrainPositionInfoType.Get(te)
|
||||
train.Up = tpi.Up
|
||||
train.Len = int64(tpi.Len)
|
||||
train.HeadLink = tpi.HeadLink
|
||||
train.HeadLinkOffset = int64(tpi.TailLinkOffset)
|
||||
train.TailLink = tpi.TailLink
|
||||
train.TailLinkOffset = int64(tpi.HeadLinkOffset)
|
||||
return ecs.NewOkEmptyResult()
|
||||
} else {
|
||||
return ecs.NewErrResult(fmt.Errorf("列车[%s]实体不存在", tpi.TrainId))
|
||||
}
|
||||
|
||||
})
|
||||
return result.Err
|
||||
}
|
||||
|
@ -140,6 +140,9 @@ func (l *LinkPort) Port() proto.Port {
|
||||
func (l *LinkPort) Device() PortedDevice {
|
||||
return l.link
|
||||
}
|
||||
func (l *LinkPort) IsPortA() bool {
|
||||
return l.port == proto.Port_A
|
||||
}
|
||||
|
||||
type LinkRange struct {
|
||||
link *Link
|
||||
|
@ -176,6 +176,9 @@ func (s *PhysicalSection) findBoundaryKmByPort(port proto.Port) *proto.Kilometer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *PhysicalSection) LinkRanges() []*LinkRange {
|
||||
return s.linkRanges
|
||||
}
|
||||
|
||||
type PhysicalSectionPort struct {
|
||||
section *PhysicalSection
|
||||
|
@ -244,7 +244,17 @@ func (t *Turnout) FindLinkPositionByPort(port proto.Port) *LinkPosition {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Turnout) FindLinkByPort(port proto.Port) *LinkPort {
|
||||
switch port {
|
||||
case proto.Port_A:
|
||||
return t.aLinkPort
|
||||
case proto.Port_B:
|
||||
return t.bLinkPort
|
||||
case proto.Port_C:
|
||||
return t.cLinkPort
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (t *Turnout) SwitchMachineType() proto.Turnout_SwitchMachineType {
|
||||
return t.switchMachineType
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
package device_sys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/yohamta/donburi"
|
||||
"joylink.club/ecs"
|
||||
"joylink.club/ecs/filter"
|
||||
"joylink.club/rtsssimulation/component"
|
||||
"joylink.club/rtsssimulation/entity"
|
||||
"joylink.club/rtsssimulation/repository"
|
||||
"joylink.club/rtsssimulation/repository/model/proto"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
// SectionDetectSystem 区段检测系统
|
||||
@ -23,7 +28,8 @@ func (s *SectionDetectSystem) Update(w ecs.World) {
|
||||
//所有列车
|
||||
s.trainQuery.Each(w, func(entry *donburi.Entry) {
|
||||
tp := component.TrainPositionInfoType.Get(entry)
|
||||
for _, sectionId := range tp.SectionIds { //车所在区段
|
||||
trainSectionIds := s.doSearchTrainOccupiedSections(w, tp)
|
||||
for _, sectionId := range trainSectionIds { //车所在区段
|
||||
tc, find := sectionTrainMap[sectionId]
|
||||
if !find {
|
||||
tc = newTrainCount()
|
||||
@ -55,3 +61,185 @@ func newTrainCount() *trainCount {
|
||||
func (c *trainCount) add() {
|
||||
c.count++
|
||||
}
|
||||
|
||||
func (s *SectionDetectSystem) doSearchTrainOccupiedSections(w ecs.World, tp *component.TrainPositionInfo) []string {
|
||||
wd := entity.GetWorldData(w)
|
||||
curLink := wd.Repo.FindLink(tp.HeadLink)
|
||||
stp := &stpContext{w: w, trainLen: tp.Len, curLink: curLink, curOffset: tp.HeadLinkOffset, searchDirection: !tp.Up, acLen: 0}
|
||||
c := 0
|
||||
for stp.needAccumulate() {
|
||||
c++
|
||||
if c > 50 {
|
||||
slog.Warn("======>>>>搜索列车所占物理区段,迭代次数过多!!!!")
|
||||
break
|
||||
}
|
||||
stp.accumulateLen()
|
||||
if stp.needAccumulate() {
|
||||
stp.nextLink()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
//
|
||||
return stp.trainSections()
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
type stpContext struct {
|
||||
w ecs.World
|
||||
trainLen int64 //列车长度
|
||||
curLink *repository.Link //当前迭代的link
|
||||
curOffset int64 //当前迭代的link,长度累加起点
|
||||
searchDirection bool //在curLink上长度累加的方向,true:a->b,false:b->a,a->b偏移量变大
|
||||
acLen int64 //当前累加长度
|
||||
acRanges []*stpLinkRange //轨道range列表
|
||||
}
|
||||
|
||||
// 获取列车所占的物理区段
|
||||
func (s *stpContext) trainSections() []string {
|
||||
secs := make(map[string]string)
|
||||
for _, acR := range s.acRanges {
|
||||
ids := acR.sectionIds()
|
||||
for _, id := range ids {
|
||||
secs[id] = id
|
||||
}
|
||||
}
|
||||
var sectionIds []string
|
||||
for _, id := range secs {
|
||||
sectionIds = append(sectionIds, id)
|
||||
}
|
||||
return sectionIds
|
||||
}
|
||||
func (s *stpContext) needAccumulate() bool {
|
||||
return s.curLink != nil && s.acLen < s.trainLen
|
||||
}
|
||||
func (s *stpContext) nextLink() {
|
||||
var nextLinkPort *repository.LinkPort
|
||||
if s.searchDirection {
|
||||
bDc := s.curLink.BRelation()
|
||||
bDcDw := s.turnoutPosition(bDc.Turnout().Id())
|
||||
switch bDc.Port() {
|
||||
case proto.Port_A: //link-b连接turnout-A
|
||||
if bDcDw {
|
||||
nextLinkPort = bDc.Turnout().FindLinkByPort(proto.Port_B)
|
||||
} else {
|
||||
nextLinkPort = bDc.Turnout().FindLinkByPort(proto.Port_C)
|
||||
}
|
||||
case proto.Port_B: //link-b连接turnout-B
|
||||
fallthrough
|
||||
case proto.Port_C: //link-b连接turnout-C
|
||||
nextLinkPort = bDc.Turnout().FindLinkByPort(proto.Port_A)
|
||||
}
|
||||
} else {
|
||||
aDc := s.curLink.ARelation()
|
||||
aDcDw := s.turnoutPosition(aDc.Turnout().Id())
|
||||
switch aDc.Port() {
|
||||
case proto.Port_A: //link-a连接turnout-A
|
||||
if aDcDw {
|
||||
nextLinkPort = aDc.Turnout().FindLinkByPort(proto.Port_B)
|
||||
} else {
|
||||
nextLinkPort = aDc.Turnout().FindLinkByPort(proto.Port_C)
|
||||
}
|
||||
case proto.Port_B: //link-a连接turnout-B
|
||||
fallthrough
|
||||
case proto.Port_C: //link-a连接turnout-C
|
||||
nextLinkPort = aDc.Turnout().FindLinkByPort(proto.Port_A)
|
||||
}
|
||||
}
|
||||
//
|
||||
if nextLinkPort != nil {
|
||||
s.curLink = nextLinkPort.Device().(*repository.Link)
|
||||
fromA := nextLinkPort.IsPortA()
|
||||
s.searchDirection = fromA
|
||||
if fromA {
|
||||
s.curOffset = 0
|
||||
} else {
|
||||
s.curOffset = s.curLink.Length()
|
||||
}
|
||||
} else {
|
||||
slog.Warn("区段检测时,获取列车下的link失败")
|
||||
}
|
||||
}
|
||||
|
||||
// 获取道岔实际位置
|
||||
func (s *stpContext) turnoutPosition(id string) bool {
|
||||
wd := entity.GetWorldData(s.w)
|
||||
entry, ok := wd.EntityMap[id]
|
||||
if ok {
|
||||
return component.TurnoutPositionType.Get(entry).Dw
|
||||
} else {
|
||||
panic(fmt.Sprintf("道岔[%s]的实体不存在", id))
|
||||
}
|
||||
}
|
||||
|
||||
// 累加
|
||||
func (s *stpContext) accumulateLen() {
|
||||
if s.searchDirection {
|
||||
dl := s.curLink.Length() - s.curOffset
|
||||
if s.acLen+dl < s.trainLen {
|
||||
s.addLinkRange(&stpLinkRange{link: s.curLink, start: s.curOffset, end: s.curLink.Length()})
|
||||
s.acLen += dl
|
||||
} else {
|
||||
tl := s.trainLen - s.acLen
|
||||
s.addLinkRange(&stpLinkRange{link: s.curLink, start: s.curOffset, end: s.curOffset + tl})
|
||||
s.acLen += tl
|
||||
}
|
||||
} else {
|
||||
dl := s.curOffset
|
||||
if s.acLen+dl < s.trainLen {
|
||||
s.addLinkRange(&stpLinkRange{link: s.curLink, start: 0, end: s.curOffset})
|
||||
s.acLen += dl
|
||||
} else {
|
||||
tl := s.trainLen - s.acLen
|
||||
s.addLinkRange(&stpLinkRange{link: s.curLink, start: s.curOffset - tl, end: s.curOffset})
|
||||
s.acLen += tl
|
||||
}
|
||||
}
|
||||
}
|
||||
func (s *stpContext) addLinkRange(r *stpLinkRange) {
|
||||
s.acRanges = append(s.acRanges, r)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
type stpLinkRange struct {
|
||||
link *repository.Link
|
||||
start int64
|
||||
end int64
|
||||
}
|
||||
|
||||
// 获取link range 上的物理区段的id
|
||||
func (s *stpLinkRange) sectionIds() []string {
|
||||
var ids []string
|
||||
ps := s.link.PhysicalSections()
|
||||
for _, p := range ps {
|
||||
for _, pr := range p.LinkRanges() {
|
||||
if isRangeOverlap(s.start, s.end, pr.Start(), pr.End()) {
|
||||
ids = append(ids, p.Id())
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
func isRangeOverlap(r1Start int64, r1End int64, r2Start int64, r2End int64) bool {
|
||||
r1Start, r1End = formatRange(r1Start, r1End)
|
||||
r2Start, r2End = formatRange(r2Start, r2End)
|
||||
if r2Start > r1Start && r2Start < r1End {
|
||||
return true
|
||||
}
|
||||
if r2End > r1Start && r2End < r1End {
|
||||
return true
|
||||
}
|
||||
if r1Start == r2Start && r1End == r2End {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func formatRange(start int64, end int64) (int64, int64) {
|
||||
if start < end {
|
||||
return start, end
|
||||
} else {
|
||||
return end, start
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user