Merge remote-tracking branch 'origin/master'

This commit is contained in:
joylink_zhangsai 2023-09-14 15:07:21 +08:00
commit 5e7897ccf3
38 changed files with 1428 additions and 3017 deletions

View File

@ -1,15 +0,0 @@
package components
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/components/cstate"
)
// 按钮状态组件
var ButtonStateComponent = ecs.NewComponentType[cstate.ButtonState]()
// 按钮操作组件
var ButtonPressOperatingComponent = ecs.NewComponentType[cstate.ButtonPressOperating]()
// 按钮确认组件
var ButtonConfirmOperatingComponent = ecs.NewComponentType[cstate.ButtonConfirmOperating]()

View File

@ -1,60 +0,0 @@
package components
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/components/cstate"
)
// 系统时钟组件
var SystemTimerComponent = ecs.NewComponentType[cstate.SystemTimer]()
// 模型仓库引用组件,单例
var ModelStorageRefComponent = ecs.NewComponentType[cstate.ModelStorageRef]()
// 身份组件
var DeviceIdentityComponent = ecs.NewComponentType[cstate.DeviceIdentity]()
// 存储屏蔽门标签组件
var PsdTagHandlerComponent = ecs.NewComponentType[cstate.EntityTagHandler]()
// 存储继电器标签组件
var RelayTagHandlerComponent = ecs.NewComponentType[cstate.EntityTagHandler]()
// 可移动设备组件
var MovableDeviceStateComponent = ecs.NewComponentType[cstate.MovableDeviceState]()
// 比率设备组件
var PercentageDeviceStateComponent = ecs.NewComponentType[cstate.PercentageDeviceState]()
// 道岔继电器状态组件
var SwitchRelayStateComponent = ecs.NewComponentType[cstate.SwitchRelayState]()
// 物理区段状态组件
var PhysicalSectionStateComponent = ecs.NewComponentType[cstate.PhysicalSectionState]()
// 信号机状态组件
var SignalStateComponent = ecs.NewComponentType[cstate.SignalState]()
// 站台单侧屏蔽门状态组件
var PsdStateComponent = ecs.NewComponentType[cstate.PsdState]()
// 应答器状态组件
var BaliseStateComponent = ecs.NewComponentType[cstate.BaliseState]()
// 列车状态组件
var TrainStateComponent = ecs.NewComponentType[cstate.TrainState]()
// 两档按钮/旋钮状态组件
var TowPositionButtonStateComponent = ecs.NewComponentType[cstate.TowPositionButtonState]()
// 继电器状态组件
var RelayStateComponent = ecs.NewComponentType[cstate.RelayState]()
// 紧急停车按钮状态组件
var EmpStateComponent = ecs.NewComponentType[cstate.EmpState]()
// 生成标签组件
// 用于标记实体便于查找
func NewComponentTag() *ecs.ComponentType[struct{}] {
return ecs.NewComponentType[struct{}]()
}

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +0,0 @@
package cstate
import (
"time"
"github.com/yohamta/donburi/component"
"joylink.club/rtsssimulation/umi"
)
// 此文件中为与设备无关的仿真系统自身的状态定义
// 系统时钟,单例
type SystemTimer struct {
timer *time.Time
}
// 以指定时间构建
func NewSystemTimer(time *time.Time) *SystemTimer {
return &SystemTimer{
timer: time,
}
}
// 重置时间
func (me *SystemTimer) ResetTime(time time.Time) {
*me.timer = time
}
// 获取当前时间的副本
func (me *SystemTimer) Now() time.Time {
return *me.timer
}
// tick系统时钟,单位ms
func (me *SystemTimer) Tick(tick int) {
*me.timer = me.timer.Add(time.Duration(tick) * time.Millisecond)
}
/////////////////////////////////////////////////////////
// 实体标签
type EntityTag = component.IComponentType
type EntityTagHandler struct {
Tag EntityTag
}
/////////////////////////////////////////////////////////
// 模型仓库引用
// 用于world内使用查询模型
type ModelStorageRef struct {
ModelManager umi.IModelManager
}

View File

@ -1,156 +0,0 @@
package creator
import (
"time"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/system"
"joylink.club/rtsssimulation/umi"
)
// 仿真world配置
type WorldConfig struct {
//模型管理器,接收模型仓库管理器实例的指针
ModelManager umi.IModelManager
//world 系统
Systems []ecs.ISystem
//world tick
Tick int
//world 起始时间
InitTime time.Time
}
// 初始化仿真world
func InitializeWorld(config *WorldConfig) ecs.World {
world := ecs.NewWorld(config.Tick)
// 初始化系统
for _, sys := range config.Systems {
world.AddSystem(sys)
}
// 初始化实体
initEntites(config, world)
//
return world
}
// 初始化实体
func initEntites(config *WorldConfig, world ecs.World) {
modelStorageRefEntry := CreateModelStorageRefEntity(world)
components.ModelStorageRefComponent.Set(modelStorageRefEntry, &cstate.ModelStorageRef{ModelManager: config.ModelManager})
//world time
worldTime := CreateWorldTimeEntity(world)
components.SystemTimerComponent.Set(worldTime, cstate.NewSystemTimer(&config.InitTime))
//
foreachModels(config.ModelManager, umi.Switch, func(md umi.IDeviceModel) {
entry := CreateSwitchEntity(world)
components.DeviceIdentityComponent.Set(entry, &cstate.DeviceIdentity{Id: md.GetId()})
components.SwitchRelayStateComponent.Set(entry, &cstate.SwitchRelayState{DcJ: false, FcJ: false, DbJ: true, FbJ: false})
components.PercentageDeviceStateComponent.Set(entry, &cstate.PercentageDeviceState{Rate: system.SwitchNormalVaule, Target: system.SwitchNormalVaule})
components.MovableDeviceStateComponent.Set(entry, &cstate.MovableDeviceState{ToH: false, Speed: 0, Position: system.SwitchNormalVaule})
})
//
foreachModels(config.ModelManager, umi.Signal, func(md umi.IDeviceModel) {
entry := CreateSignalEntity(world)
components.DeviceIdentityComponent.Set(entry, &cstate.DeviceIdentity{Id: md.GetId()})
components.SignalStateComponent.Set(entry, &cstate.SignalState{Display: cstate.SignalAspect_No})
})
//
foreachModels(config.ModelManager, umi.Psd, func(md umi.IDeviceModel) {
psdEntry := CreatePsdEntity(world)
components.DeviceIdentityComponent.Set(psdEntry, &cstate.DeviceIdentity{Id: md.GetId()})
components.PsdStateComponent.Set(psdEntry, &cstate.PsdState{AllClosed: true, AllOpened: false, InterlockReleased: false})
//
psd := md.(umi.IPsdModel)
for _, psdCell := range psd.AllDeviceCells() {
cellEntry := CreatePsdCellEntity(world, psdEntry)
components.DeviceIdentityComponent.Set(cellEntry, &cstate.DeviceIdentity{Id: psdCell.GetId()})
components.PercentageDeviceStateComponent.Set(cellEntry, &cstate.PercentageDeviceState{Rate: system.PsdCellWholeCloseValue, Target: system.PsdCellWholeCloseValue})
components.MovableDeviceStateComponent.Set(cellEntry, &cstate.MovableDeviceState{ToH: true, Speed: 0, Position: system.PsdCellWholeCloseValue})
}
})
//
foreachModels(config.ModelManager, umi.TowPosButton, func(md umi.IDeviceModel) {
entry := CreateTowPosButtonEntity(world)
components.DeviceIdentityComponent.Set(entry, &cstate.DeviceIdentity{Id: md.GetId()})
components.TowPositionButtonStateComponent.Set(entry, &cstate.TowPositionButtonState{Pos1: false, Pos2: true})
})
}
func foreachModels(modelManager umi.IModelManager, deviceType umi.DeviceType, eachFunc func(deviceModel umi.IDeviceModel)) {
for _, model := range modelManager.FindByType(deviceType) {
eachFunc(model)
}
}
// //////////////////////////////////////////////////////////////////////
// 创建模型仓库引用实体
func CreateModelStorageRefEntity(w ecs.World) *ecs.Entry {
return w.Create(components.ModelStorageRefComponent)
}
// 创建world time 实体
func CreateWorldTimeEntity(w ecs.World) *ecs.Entry {
return w.Create(components.SystemTimerComponent)
}
// 创建道岔实体
func CreateSwitchEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.SwitchRelayStateComponent, components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent, components.RelayTagHandlerComponent)
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}
// 创建信号机实体
func CreateSignalEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.SignalStateComponent, components.RelayTagHandlerComponent)
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}
// 创建物理区段实体
func CreatePhysicalSectionEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.PhysicalSectionStateComponent)
}
// 创建站台单侧屏蔽门实体
func CreatePsdEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.PsdStateComponent, components.PsdTagHandlerComponent, components.RelayTagHandlerComponent)
components.PsdTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}
// 创建屏蔽门cell实体
func CreatePsdCellEntity(w ecs.World, psdEntry *ecs.Entry) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent, components.PsdTagHandlerComponent.Get(psdEntry).Tag)
}
// 创建应答器实体
func CreateBaliseEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.BaliseStateComponent)
}
// 创建列车实体
func CreateTrainEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.TrainStateComponent)
}
// 创建两档位按钮实体
func CreateTowPosButtonEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.TowPositionButtonStateComponent)
}
// 创建继电器实体
// deviceEntry: 被继电器控制的设备
func CreateRelayEntity(w ecs.World, deviceEntry *ecs.Entry) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.RelayStateComponent, components.RelayTagHandlerComponent.Get(deviceEntry).Tag)
}
// 创建紧急停车按钮实体
func CreateEmpEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.EmpStateComponent, components.RelayTagHandlerComponent)
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}

27
entities/common_entity.go Normal file
View File

@ -0,0 +1,27 @@
package entities
import (
"time"
"joylink.club/ecs"
"joylink.club/rtsssimulation/system"
)
// 创建模型仓库实体
func CreateModelStorageEntity(w ecs.World) *ecs.Entry {
return w.Create(system.ModelStorageComponent)
}
// 创建继电器实体
func CreateRelayEntity(w ecs.World, relayId string) *ecs.Entry {
e := w.Create(system.EntityIdentityComponent, system.RelayStateComponent)
system.EntityIdentityComponent.Set(e, &system.EntityIdentity{Id: relayId})
return e
}
// 创建系统时钟实体
func CreateSystemTimerEntity(w ecs.World, systemTime time.Time) *ecs.Entry {
e := w.Create(system.SystemTimerComponent)
system.SystemTimerComponent.Set(e, system.NewSystemTimer(&systemTime))
return e
}

13
entities/signal_entity.go Normal file
View File

@ -0,0 +1,13 @@
package entities
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/system"
)
func CreateSignal3XH1Entity(w ecs.World, signalId string) *ecs.Entry {
e := w.Create(system.EntityIdentityComponent, system.Signal3XH1StateComponent)
system.EntityIdentityComponent.Set(e, &system.EntityIdentity{Id: signalId})
system.Signal3XH1StateComponent.Set(e, system.NewSignal3XH1State())
return e
}

24
entities/switch_entity.go Normal file
View File

@ -0,0 +1,24 @@
package entities
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/system"
)
// 双机zdj9
// 默认定位
func CreateSwitch2jzdj9Entity(w ecs.World, switchId string) *ecs.Entry {
e := w.Create(system.EntityIdentityComponent, system.Switch2jZdj9StateComponent, system.MovableObject1Component, system.MovableObject2Component)
system.EntityIdentityComponent.Set(e, &system.EntityIdentity{Id: switchId})
//电路
system.Switch2jZdj9StateComponent.Set(e, system.NewSwitch2jZdj9State())
//J1
j1 := system.NewMovableObject()
j1.Value = system.J1Range
system.MovableObject1Component.Set(e, j1)
//J2
j2 := system.NewMovableObject()
j2.Value = system.J2Range
system.MovableObject2Component.Set(e, j2)
return e
}

View File

@ -1,132 +1,5 @@
package main
import (
"time"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/creator"
"joylink.club/rtsssimulation/examples/test1/tmodel"
"joylink.club/rtsssimulation/examples/test1/tstorages"
"joylink.club/rtsssimulation/operate"
"joylink.club/rtsssimulation/system"
)
// 具体共享模型仓库key
var StorageKeyXaV1 = tstorages.StorageKey{LineId: "xa-1", Version: "0.1"}
func main() {
initShareModels()
// 通过共享仓库生成具体仿真world的模型仓库
woldModelStorage := tstorages.ShareStoragesMapper.CreateWorldStorageWithShare(StorageKeyXaV1, initLinkModels())
//
config := &creator.WorldConfig{
ModelManager: woldModelStorage,
Tick: 300,
InitTime: time.Now(),
Systems: []ecs.ISystem{
system.NewMovableDeviceSystem(),
system.NewPercentageDeviceSystem(),
system.NewSwitchSystem(),
system.NewPsdSystem(),
system.NewTimerSystem(),
system.NewDebugSystem()},
}
world := creator.InitializeWorld(config)
//
world.StartUp()
//
time.Sleep(2 * time.Second)
//
//testPsdOpt(world)
//testPsdCellOpt(world)
testSwitchTurn(world)
//
time.Sleep(120 * time.Second)
}
// 构建具体仿真link模型
func initLinkModels() *tstorages.ModelStorage {
mds := tstorages.NewModelStorage()
//
link1 := tmodel.NewLinkModel("link1")
link2 := tmodel.NewLinkModel("link2")
mds.AddModel(link1)
mds.AddModel(link2)
return mds
}
// 构建模型
func initShareModels() {
mds := tstorages.NewModelStorage()
//
signal1 := tmodel.NewSignalModel("signal1")
signal2 := tmodel.NewSignalModel("signal2")
mds.AddModel(signal1)
mds.AddModel(signal2)
//
switch1 := tmodel.NewSwitchModel("switch1")
switch1.TurnTime = 3000
switch2 := tmodel.NewSwitchModel("switch2")
switch2.TurnTime = 2500
mds.AddModel(switch1)
mds.AddModel(switch2)
//
psd1 := tmodel.NewPsdModel("psd1")
psd1.MoveTime = 5000
psd1Cell1 := tmodel.NewPsdCellModel("psd1Cell1", psd1)
psd1Cell2 := tmodel.NewPsdCellModel("psd1Cell2", psd1)
psd2 := tmodel.NewPsdModel("psd2")
psd2.MoveTime = 6000
psd2Cell1 := tmodel.NewPsdCellModel("psd2Cell1", psd2)
psd2Cell2 := tmodel.NewPsdCellModel("psd2Cell2", psd2)
mds.AddModel(psd1)
mds.AddModel(psd1Cell1)
mds.AddModel(psd1Cell2)
mds.AddModel(psd2)
mds.AddModel(psd2Cell1)
mds.AddModel(psd2Cell2)
//
button1 := tmodel.NewTowPosButtonModel("button1")
mds.AddModel(button1)
//
tstorages.ShareStoragesMapper.AddShareModelStorage(StorageKeyXaV1, mds)
}
////////////////////////////////////////////////////////////////
func testPsdOpt(w ecs.World) {
operate.FirePsdOperation(w, "psd1", true)
time.Sleep(5 * time.Second)
operate.FirePsdOperation(w, "psd1", false)
}
func testPsdCellOpt(w ecs.World) {
operate.FirePsdCellOperation(w, "psd1", "psd1Cell1", 0)
operate.FirePsdCellOperation(w, "psd1", "psd1Cell2", 0)
time.Sleep(10 * time.Second)
operate.FirePsdCellOperation(w, "psd1", "psd1Cell1", 100-20)
operate.FirePsdCellOperation(w, "psd1", "psd1Cell2", 100)
//
time.Sleep(10 * time.Second)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell1", 0)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell2", 0)
time.Sleep(10 * time.Second)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell1", 100-20)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell2", 100)
}
func testSwitchTurn(w ecs.World) {
operate.FireSwitchFcj(w, "switch1")
time.Sleep(3 * time.Second)
operate.FireSwitchDcj(w, "switch1")
}
func testSignalOpt(w ecs.World) {
operate.SetSignalDisplay(w, "siganl1", cstate.SignalAspect_B)
}
func testButtonOpt(world ecs.World) {
operate.FireTowPositionButtonMoving(world, "button1")
time.Sleep(3 * time.Second)
operate.FireTowPositionButtonArrivedPos1(world, "button1")
time.Sleep(3 * time.Second)
operate.FireTowPositionButtonArrivedPos2(world, "button1")
}

View File

@ -0,0 +1,6 @@
package tmodel
// 继电器模型
type RelayModel struct {
DeviceModel
}

View File

@ -1,7 +1,6 @@
package tmodel
import (
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/umi"
)
@ -10,10 +9,6 @@ type SignalModel struct {
DeviceModel
//信号机所在轨道
LinkOffset *LinkOffsetRef
//信号机类型,出厂已确定,即几个色灯、排列顺序
Type cstate.SignalAspect
//默认显示信号
DefaultDisplay cstate.SignalAspect
}
func NewSignalModel(id string) *SignalModel {

View File

@ -4,6 +4,16 @@ import (
"joylink.club/rtsssimulation/umi"
)
// 道岔电路系统中的继电器
type SwitchRelay struct {
//继电器模型
Relay umi.IRelayModel
//该继电器在该道岔电路系统中的组合类型
RelayGroup string
//该继电器在该道岔电路系统中的功能名称
RelayName string
}
// 道岔
type SwitchModel struct {
DeviceModel
@ -13,19 +23,14 @@ type SwitchModel struct {
PortB umi.ILinkRef
//道岔C端口连接的轨道
PortC umi.ILinkRef
//道岔转动需要的时间(从开度0-100的时间),单位ms
TurnTime int64
//道岔电路系统中的继电器
Relays []SwitchRelay
}
func NewSwitchModel(id string) *SwitchModel {
return &SwitchModel{DeviceModel: DeviceModel{Id: id, Type: umi.Switch}}
}
// 道岔转动从0-100耗时单位ms
func (me *SwitchModel) TurningTime() int64 {
return me.TurnTime
}
// 道岔A端口连接的轨道
func (me *SwitchModel) PortALink() umi.ILinkRef {
return me.PortA
@ -41,6 +46,33 @@ func (me *SwitchModel) PortCLink() umi.ILinkRef {
return me.PortC
}
// 根据继电器id获取在具体电路中的电路角色
// relayId-继电器id
// relayGroup-继电器组合类型
// relayName-继电器在电路中的名称
// find-true找到false未找到
func (me *SwitchModel) FindCircuitRoleById(relayId string) (relayGroup string, relayName string, find bool) {
for _, sr := range me.Relays {
id := sr.Relay.(umi.IDeviceModel).GetId()
if id == relayId {
return sr.RelayGroup, sr.RelayName, true
}
}
return "", "", false
}
// 根据继电器具体电路角色来获取继电器设备模型
// relayGroup-继电器组合类型
// relayName-继电器在电路中的名称
func (me *SwitchModel) FindRelayModelByCRole(relayGroup string, relayName string) umi.IRelayModel {
for _, sr := range me.Relays {
if sr.RelayGroup == relayGroup && sr.RelayName == relayName {
return sr.Relay
}
}
return nil
}
//////////////////////////////////////////////////////////
// 道岔端口引用

View File

@ -1,28 +0,0 @@
package operate
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/system"
)
// 应答器查询
var baliseQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.BaliseStateComponent))
//
// 发送消息到应答器
// 当要清空应答器中报文时,则message=nil
func SendMessageToTransponder(world ecs.World, transponderId string, message *cstate.BaliseContent) bool {
transponderEntry := system.QueryEntityById(world, baliseQuery, transponderId)
//
if transponderEntry == nil {
return false
}
//
components.BaliseStateComponent.Get(transponderEntry).Content = message
//
return true
}

View File

@ -1,42 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
// 紧急停车按钮查询
var empQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.EmpStateComponent))
func findEmpEntry(world ecs.World, empId string) (*ecs.Entry, error) {
empEntry := system.QueryEntityById(world, empQuery, empId)
if empEntry == nil {
return nil, fmt.Errorf("紧急停车按钮[%s]实体不存在", empId)
} else {
return empEntry, nil
}
}
// 激活紧急停车按钮
func FireEmpPressed(world ecs.World, empId string) error {
entry, err := findEmpEntry(world, empId)
if err != nil {
return err
}
components.EmpStateComponent.Get(entry).Pressed = true
return nil
}
// 复位紧急停车按钮
func FireEmpReset(world ecs.World, empId string) error {
entry, err := findEmpEntry(world, empId)
if err != nil {
return err
}
components.EmpStateComponent.Get(entry).Pressed = false
return nil
}

View File

@ -1,37 +0,0 @@
package operate
import (
"fmt"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
// 触发比率设备变动到目标比率
// lhDistance: 从L到H的总耗时单位ms
// targetRateValue: 变动的最终目标比率值,[0,100000]
func FirePercentageDevice(world ecs.World, deviceEntry *ecs.Entry, lhDistance int64, targetRateValue int64) error {
if targetRateValue < system.PercentageRateValueMin || targetRateValue > system.PercentageRateValueMax {
return fmt.Errorf("targetRateValue须在[%d,%d]范围内", system.PercentageRateValueMin, system.PercentageRateValueMax)
}
//
id := components.DeviceIdentityComponent.Get(deviceEntry).Id
if !deviceEntry.HasComponent(components.PercentageDeviceStateComponent) {
return fmt.Errorf("比率设备[%s]实体中没有百分比组件", id)
}
if !deviceEntry.HasComponent(components.MovableDeviceStateComponent) {
return fmt.Errorf("比率设备[%s]实体中没有按速度移动组件", id)
}
//
speed := int32(float64(world.Tick()) * (float64(system.PercentageRateValueMax) / float64(lhDistance)))
//
percent := components.PercentageDeviceStateComponent.Get(deviceEntry)
movable := components.MovableDeviceStateComponent.Get(deviceEntry)
//
percent.Target = targetRateValue
movable.Speed = speed
movable.ToH = targetRateValue > percent.Rate
//
return nil
}

View File

@ -1,104 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
"joylink.club/rtsssimulation/umi"
)
const (
//屏蔽门完全关闭,百分比
PsdCellWholeCloseRate int8 = system.PercentageRateMax
//屏蔽门完全打开,百分比
PsdCellWholeOpenRate int8 = system.PercentageRateMin
)
// 车站单侧屏蔽门互锁解除操作
func FirePsdInterlockRelease(world ecs.World, psdId string, lockRelease bool) error {
psdEntry, err := findPsdEntry(world, psdId)
if nil != err {
return err
}
components.PsdStateComponent.Get(psdEntry).InterlockReleased = lockRelease
//
return nil
}
// 屏蔽门全开
func FirePsdWholeOpen(world ecs.World, psdId string) error {
return FirePsdOperation(world, psdId, false)
}
// 屏蔽门全关
func FirePsdWholeClose(world ecs.World, psdId string) error {
return FirePsdOperation(world, psdId, true)
}
////////////////////////////////////////////////////////////////////////////////////
// 车站单侧屏蔽门操作
// closeOpt true-关门操作false-开门操作
func FirePsdOperation(world ecs.World, psdId string, closeOpt bool) error {
psdEntry, err := findPsdEntry(world, psdId)
if nil != err {
return err
}
//屏蔽门标签
psdTag := components.PsdTagHandlerComponent.Get(psdEntry).Tag
psdCellQuery := ecs.NewQuery(filter.Contains(psdTag))
var errPercent error = nil
psdCellQuery.Each(world, func(psdCellEntry *ecs.Entry) {
if errPercent == nil {
if closeOpt {
errPercent = FirePercentageDevice(world, psdCellEntry, findPsdWholeMoveTime(world, psdId), system.GetRateValue(PsdCellWholeCloseRate))
} else {
errPercent = FirePercentageDevice(world, psdCellEntry, findPsdWholeMoveTime(world, psdId), system.GetRateValue(PsdCellWholeOpenRate))
}
}
})
//
return errPercent
}
// 车站单侧屏蔽门单元cell操作
// closeRate cell最终关上的百分比100-完全关上0-完全未关即完全打开,(0,100)内即半关闭
func FirePsdCellOperation(world ecs.World, psdId string, psdCellId string, closeRate int8) error {
if closeRate < 0 || closeRate > 100 {
return fmt.Errorf("屏蔽门单元操作closeRate(%d)不在[0,100]内", closeRate)
}
//
psdEntry, err := findPsdEntry(world, psdId)
if nil != err {
return err
}
//屏蔽门标签
psdTag := components.PsdTagHandlerComponent.Get(psdEntry).Tag
psdCellQuery := ecs.NewQuery(filter.Contains(psdTag))
psdCellEntry := system.QueryEntityById(world, psdCellQuery, psdCellId)
if psdCellEntry == nil {
return fmt.Errorf("屏蔽门[%s]的单元门[%s]的实体不存在", psdId, psdCellId)
}
//
return FirePercentageDevice(world, psdCellEntry, findPsdWholeMoveTime(world, psdId), system.GetRateValue(closeRate))
}
// 获取屏蔽门实体
func findPsdEntry(world ecs.World, psdId string) (*ecs.Entry, error) {
psdEntry := system.QueryEntityById(world, system.PsdQuery, psdId)
if psdEntry == nil {
return nil, fmt.Errorf("屏蔽门[%s]实体不存在", psdId)
} else {
return psdEntry, nil
}
}
// 获取屏蔽门从完全开到完全关所需时间单位ms
func findPsdWholeMoveTime(world ecs.World, psdId string) int64 {
psd := system.WorldModelStorage(world).FindById(psdId)
psdUmi := psd.(umi.IPsdModel)
return psdUmi.MovingTime()
}

View File

@ -1,38 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/system"
)
// 信号机显示状态查询
var signalQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.SignalStateComponent))
// 设置某个信号机的显示
// 返回值true-设置成功false-设置失败
func SetSignalDisplay(w ecs.World, signalId string, display cstate.SignalAspect) error {
signalEntry, err := findSignalEntry(w, signalId)
if err != nil {
return err
}
//
signalState := components.SignalStateComponent.Get(signalEntry)
signalState.Display = display
//
return nil
}
// 获取信号机实体
func findSignalEntry(w ecs.World, signalId string) (*ecs.Entry, error) {
var signalEntry *ecs.Entry = system.QueryEntityById(w, signalQuery, signalId)
if signalEntry != nil {
return signalEntry, nil
} else {
return nil, fmt.Errorf("信号机[%s]的实体不存在", signalId)
}
}

View File

@ -1,37 +0,0 @@
package operate
import (
"fmt"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
const (
//道岔定位
SwitchNormalRate int8 = system.PercentageRateMin
//道岔反位
SwitchReverseRate int8 = system.PercentageRateMax
)
// 道岔定操
func FireSwitchDcj(w ecs.World, switchId string) error {
return fireSwitchTurn(w, switchId, true)
}
// 道岔反操
func FireSwitchFcj(w ecs.World, switchId string) error {
return fireSwitchTurn(w, switchId, false)
}
func fireSwitchTurn(w ecs.World, switchId string, turnNormal bool) error {
var switchEntry *ecs.Entry = system.QueryEntityById(w, system.SwitchQuery, switchId)
if switchEntry == nil {
return fmt.Errorf("道岔[%s]的实体不存在", switchId)
}
relay := components.SwitchRelayStateComponent.Get(switchEntry)
relay.DcJ = turnNormal
relay.FcJ = !turnNormal
//
return nil
}

View File

@ -1,56 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
var towPosButtonsQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.TowPositionButtonStateComponent))
// 档位变换过程中指令
// 该指令执行后,按钮处于未知状态
func FireTowPositionButtonMoving(w ecs.World, buttonId string) error {
entry := system.QueryEntityById(w, towPosButtonsQuery, buttonId)
if nil == entry {
return fmt.Errorf("两档位按钮[%s]实体不存在", buttonId)
}
//
state := components.TowPositionButtonStateComponent.Get(entry)
state.Pos1 = false
state.Pos2 = false
//
return nil
}
// 档位变换到达pos1指令
// 执行该指令后按钮处于pos1稳定态
func FireTowPositionButtonArrivedPos1(w ecs.World, buttonId string) error {
return fireTowPositionButtonArrivedPos(w, buttonId, true)
}
// 档位变换到达pos2指令
// 执行该指令后按钮处于pos2稳定态
func FireTowPositionButtonArrivedPos2(w ecs.World, buttonId string) error {
return fireTowPositionButtonArrivedPos(w, buttonId, false)
}
func fireTowPositionButtonArrivedPos(w ecs.World, buttonId string, arrivedPos1 bool) error {
entry := system.QueryEntityById(w, towPosButtonsQuery, buttonId)
if nil == entry {
return fmt.Errorf("两档位按钮[%s]实体不存在", buttonId)
}
//
state := components.TowPositionButtonStateComponent.Get(entry)
if arrivedPos1 {
state.Pos1 = true
state.Pos2 = false
} else {
state.Pos1 = false
state.Pos2 = true
}
//
return nil
}

20
simulation/config.go Normal file
View File

@ -0,0 +1,20 @@
package simulation
import (
"time"
"joylink.club/ecs"
"joylink.club/rtsssimulation/umi"
)
// 仿真world配置
type WorldConfig struct {
//模型管理器,接收模型仓库管理器实例的指针
ModelManager umi.IModelManager
//world 系统
Systems []ecs.ISystem
//world tick
Tick int
//world 起始时间
InitTime time.Time
}

19
simulation/init.go Normal file
View File

@ -0,0 +1,19 @@
package simulation
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/entities"
)
// 初始化仿真world
func InitializeWorld(config *WorldConfig) ecs.World {
world := ecs.NewWorld(config.Tick)
// 初始化系统
for _, sys := range config.Systems {
world.AddSystem(sys)
}
// 初始化系统时间
entities.CreateSystemTimerEntity(world, config.InitTime)
//
return world
}

View File

@ -1,104 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
// 按钮系统
type ButtonSystem struct {
}
// 按钮组件
var btnIdCom, btnStaCom, btnPreOperCom, btnConOperCom = components.DeviceIdentityComponent,
components.ButtonStateComponent, components.ButtonPressOperatingComponent, components.ButtonConfirmOperatingComponent
// 查询
var btnIdQuery = ecs.NewQuery(filter.Contains(btnIdCom))
var btnUpdateQuery = ecs.NewQuery(filter.Contains(btnStaCom, btnPreOperCom, btnConOperCom))
func NewButtonSystem() *ButtonSystem {
return &ButtonSystem{}
}
// 按钮操作
func PressDownAndUpButton(w ecs.World, btnId string, down bool) bool {
buttonEntry := queryButton(w, btnId)
if buttonEntry == nil {
return false
}
t, b := getButtonBaseInfo(btnId)
if !buttonEntry.HasComponent(btnPreOperCom) { // 操作组件
buttonEntry.AddComponent(btnPreOperCom)
}
preOper := btnPreOperCom.Get(buttonEntry)
preOper.Start, preOper.Down, preOper.NeedConfirm, preOper.OperateTime = true, down, b, t
return true
}
// 确认操作
func ConfirmButton(w ecs.World, btnId string, confirm bool) bool {
buttonEntry := queryButton(w, btnId)
if buttonEntry == nil {
return false
}
if !buttonEntry.HasComponent(btnConOperCom) { // 确认组件
buttonEntry.AddComponent(btnConOperCom)
}
conOper := btnConOperCom.Get(buttonEntry)
conOper.Confirm, conOper.Cancel = confirm, !confirm
return true
}
// 更新按钮状态
func (bs *ButtonSystem) Update(w ecs.World) {
btnUpdateQuery.Each(w, func(e *ecs.Entry) {
if e.HasComponent(btnPreOperCom) {
btnPreOper := btnPreOperCom.Get(e)
if btnPreOper.Start { // 按钮开始操作
if btnPreOper.OperateTime <= 0 { // 按钮操作时间大于0
btnPreOper.Start, btnPreOper.OperateTime = false, 0
} else {
btnPreOper.OperateTime -= int64(w.Tick())
if btnPreOper.NeedConfirm {
conOper := btnConOperCom.Get(e)
if e.HasComponent(btnConOperCom) && (conOper.Cancel || conOper.Confirm) {
if conOper.Confirm {
btnSta := btnStaCom.Get(e)
btnSta.PressDown = btnPreOper.Down
}
btnPreOper.Start, btnPreOper.OperateTime = false, 0
conOper.Cancel, conOper.Confirm = false, false
e.RemoveComponent(btnPreOperCom)
e.RemoveComponent(btnConOperCom)
}
} else {
btnSta := btnStaCom.Get(e)
btnSta.PressDown = btnPreOper.Down
btnPreOper.Start, btnPreOper.OperateTime = false, 0
e.RemoveComponent(btnPreOperCom)
}
}
} else {
e.RemoveComponent(btnPreOperCom)
}
}
})
}
// 查找按钮
func queryButton(w ecs.World, btnId string) *ecs.Entry {
var buttonEntry *ecs.Entry = nil
btnIdQuery.Each(w, func(e *ecs.Entry) {
if id := btnIdCom.Get(e).Id; id == btnId {
buttonEntry = e
}
})
return buttonEntry
}
// 获取按钮设置信息
func getButtonBaseInfo(btnId string) (int64, bool) {
return 15, false
}

View File

@ -1,123 +0,0 @@
package system
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
// 调试时显示一些信息
type DebugSystem struct {
}
func NewDebugSystem() *DebugSystem {
return &DebugSystem{}
}
// world 执行
func (me *DebugSystem) Update(w ecs.World) {
//debugMovableDevice(w)
//debugPsd(w)
debugSwitch(w)
//debugSignal(w)
//debugTowPosButton(w)
}
// 可按速度移动组件
func debugMovableDevice(w ecs.World) {
query := ecs.NewQuery(filter.Contains(components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent))
query.Each(w, func(e *ecs.Entry) {
id := components.DeviceIdentityComponent.Get(e).Id
if "psd1Cell1" == id {
percent := components.PercentageDeviceStateComponent.Get(e)
movable := components.MovableDeviceStateComponent.Get(e)
fmt.Printf("==>>屏蔽门cell [%s],curRateValue = %d ,targetRateValue = %d , speed = %d position = %d\n", id, percent.Rate, percent.Target, movable.Speed, movable.Position)
}
})
}
// 两档位按钮旋钮
func debugTowPosButton(w ecs.World) {
towPosButtonsQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.TowPositionButtonStateComponent))
towPosButtonsQuery.Each(w, func(e *ecs.Entry) {
id := components.DeviceIdentityComponent.Get(e).Id
state := components.TowPositionButtonStateComponent.Get(e)
switch {
case state.Pos1 && !state.Pos2:
{
fmt.Printf("两档位按钮[%s],处于 一 档稳态\n", id)
}
case !state.Pos1 && state.Pos2:
{
fmt.Printf("两档位按钮[%s],处于 二 档稳态\n", id)
}
case !state.Pos1 && !state.Pos2:
{
fmt.Printf("两档位按钮[%s],处于未知或变换过程中 ......\n", id)
}
default:
{
fmt.Printf("两档位按钮[%s],异常同时处于 一二 档 \n", id)
}
}
})
}
// 屏蔽门状态
func debugPsd(w ecs.World) {
psdQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.PsdStateComponent, components.PsdTagHandlerComponent))
psdQuery.Each(w, func(e *ecs.Entry) {
psdId := components.DeviceIdentityComponent.Get(e).Id
psdState := components.PsdStateComponent.Get(e)
psdTag := components.PsdTagHandlerComponent.Get(e).Tag
fmt.Printf("屏蔽门[%s] ,全关=%t ,全开=%t ,互锁解除=%t > ", psdId, psdState.AllClosed, psdState.AllOpened, psdState.InterlockReleased)
//
psdCellQuery := ecs.NewQuery(filter.Contains(psdTag))
psdCellQuery.Each(w, func(e *ecs.Entry) {
psdCellId := components.DeviceIdentityComponent.Get(e).Id
psdCellPercent := components.PercentageDeviceStateComponent.Get(e)
psdCellMovable := components.MovableDeviceStateComponent.Get(e)
//
fmt.Printf("|| cell[%s] ,closeRate=%d ", psdCellId, GetRate(psdCellPercent.Rate))
if psdCellMovable.Speed > 0 {
if psdCellMovable.ToH {
fmt.Printf("== 关门操作中,移动速率=%d", psdCellMovable.Speed)
} else {
fmt.Printf("== 开门操作中,移动速率=%d", psdCellMovable.Speed)
}
}
})
//
fmt.Println()
})
}
// 显示信号机状态
func debugSignal(w ecs.World) {
siganlQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.SignalStateComponent))
siganlQuery.Each(w, func(e *ecs.Entry) {
id := components.DeviceIdentityComponent.Get(e).Id
state := components.SignalStateComponent.Get(e)
fmt.Printf("==>>信号机[%s],显示=%d\n", id, state.Display)
})
}
// 显示道岔状态
func debugSwitch(w ecs.World) {
switchesQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.SwitchRelayStateComponent))
switchesQuery.Each(w, func(e *ecs.Entry) {
percent := components.PercentageDeviceStateComponent.Get(e)
movable := components.MovableDeviceStateComponent.Get(e)
id := components.DeviceIdentityComponent.Get(e).Id
curRate := GetRate(percent.Rate)
j := components.SwitchRelayStateComponent.Get(e)
fmt.Printf("道岔 [%s],当前位置百分比 [%d] ,Dcj = %t, Fcj = %t, Dbj = %t ,Fbj = %t ,", id, curRate, j.DcJ, j.FcJ, j.DbJ, j.FbJ)
if movable.Speed > 0 {
fmt.Printf(" ==> 正在转动,移动速率[%d]", movable.Speed)
}
fmt.Println()
})
}

View File

@ -1,38 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/umi"
)
// 紧急停车按钮继电器系统
type EmpRelaySystem struct {
relaySystem
// 紧急停车按钮查询
query *ecs.Query
}
func NewEmpRelaySystem() *EmpRelaySystem {
return &EmpRelaySystem{
relaySystem: relaySystem{relayQuery: make(map[string]*ecs.Query)},
query: ecs.NewQuery(filter.Contains(components.EmpStateComponent)),
}
}
// world 执行
func (me *EmpRelaySystem) Update(world ecs.World) {
me.query.Each(world, func(empEntry *ecs.Entry) {
//key-继电器作用名value-继电器实体
usageRelayMapper := make(map[string]*ecs.Entry)
//迭代关联的所有继电器
me.getDeviceRelayQuery(empEntry).Each(world, func(empRelayEntry *ecs.Entry) {
relayId := components.DeviceIdentityComponent.Get(empRelayEntry).Id
relayModel := (WorldModelStorage(world).FindById(relayId)).(umi.IRelayModel)
usageRelayMapper[relayModel.UsageName()] = empRelayEntry
})
//根据具体业务逻辑处理继电器
})
}

View File

@ -0,0 +1,27 @@
package sysEvent
import "joylink.club/ecs"
//继电器动作事件
//由继电器实体系统产生,表示继电器吸合落下动作
type RelayActionEvent struct {
//继电器id
Id string
//true -吸合
Xh bool
}
//继电器状态须改变事件
//由电路系统运算发现某个继电器需要改变,则由电路系统产生该事件来通知对应继电器产生对应动作
type RelayNeedChangeEvent struct {
//继电器id
Id string
//true -吸合
Xh bool
}
//继电器动作事件总线
var RelayActionEventBus = ecs.NewEventType[RelayActionEvent]()
//继电器状态须改变事件总线
var RelayNeedChangeEventBus = ecs.NewEventType[RelayNeedChangeEvent]()

View File

@ -0,0 +1,18 @@
package sysEvent
import "joylink.club/ecs"
//信号机3XH1显示状态变化事件
type Signal3XH1AspectChangedEvent struct {
//信号机id
Id string
// 物理黄灯true-亮
U bool
// 物理绿灯true-亮
L bool
// 物理红灯true-亮
H bool
}
//信号机3XH1显示状态变化事件总线
var Signal3XH1AspectChangedEventBus = ecs.NewEventType[Signal3XH1AspectChangedEvent]()

View File

@ -1,31 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
// 按速度移动的设备系统
// 只负责按速度移动位置,由该组件的观察者负责解释位置
type MovableDeviceSystem struct {
query *ecs.Query
}
func NewMovableDeviceSystem() *MovableDeviceSystem {
return &MovableDeviceSystem{query: ecs.NewQuery(filter.Contains(components.MovableDeviceStateComponent))}
}
// world 执行
func (me *MovableDeviceSystem) Update(world ecs.World) {
me.query.Each(world, func(e *ecs.Entry) {
md := components.MovableDeviceStateComponent.Get(e)
if md.Speed > 0 {
if md.ToH {
md.Position += int64(md.Speed)
} else {
md.Position -= int64(md.Speed)
}
}
})
}

75
system/move_system.go Normal file
View File

@ -0,0 +1,75 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
)
// 时间维度上移动的物体
type MovableObject struct {
Value int64
//移动方向0-不动1-变大,-1 -变小
direction int8
}
func NewMovableObject() *MovableObject {
return &MovableObject{Value: 0, direction: 0}
}
// 时间维度上移动物体组件
var MovableObjectComponent = ecs.NewComponentType[MovableObject]()
var MovableObject1Component = ecs.NewComponentType[MovableObject]()
var MovableObject2Component = ecs.NewComponentType[MovableObject]()
type TimeMovableSystem struct {
query *ecs.Query
}
func NewTimeMovableSystem() *TimeMovableSystem {
return &TimeMovableSystem{
query: ecs.NewQuery(filter.Or(filter.Contains(MovableObjectComponent), filter.Contains(MovableObject1Component), filter.Contains(MovableObject2Component))),
}
}
// world 执行
func (me *TimeMovableSystem) Update(w ecs.World) {
me.query.Each(w, func(e *ecs.Entry) {
if e.HasComponent(MovableObjectComponent) {
MovableObjectComponent.Get(e).move(w.Tick())
}
if e.HasComponent(MovableObject1Component) {
MovableObject1Component.Get(e).move(w.Tick())
}
if e.HasComponent(MovableObject2Component) {
MovableObject2Component.Get(e).move(w.Tick())
}
})
}
////////////////////////////////////////////////
func (me *MovableObject) move(tick int) {
if me.direction != 0 {
if me.direction > 0 {
me.Value += int64(tick)
} else {
me.Value -= int64(tick)
}
}
}
// 暂停
func (me *MovableObject) Pause() {
me.direction = 0
}
// 前进
func (me *MovableObject) Forward() {
me.direction = 1
}
// 后退
func (me *MovableObject) Retreat() {
me.direction = -1
}

View File

@ -1,63 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
type PercentageDeviceSystem struct {
query *ecs.Query
}
func NewPercentageDeviceSystem() *PercentageDeviceSystem {
return &PercentageDeviceSystem{query: ecs.NewQuery(filter.Contains(components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent))}
}
const (
PercentageRateValueMax int64 = 100000
PercentageRateValueMin int64 = 0
)
const (
PercentageRateMax int8 = 100
PercentageRateMin int8 = 0
)
// world 执行
func (me *PercentageDeviceSystem) Update(world ecs.World) {
me.query.Each(world, func(e *ecs.Entry) {
movable := components.MovableDeviceStateComponent.Get(e)
if movable.Speed > 0 {
percentage := components.PercentageDeviceStateComponent.Get(e)
if movable.ToH {
if movable.Position >= percentage.Target {
movable.Speed = 0
movable.Position = percentage.Target
}
} else {
if movable.Position <= percentage.Target {
movable.Speed = 0
movable.Position = percentage.Target
}
}
//
percentage.Rate = movable.Position
}
})
}
// 映射百分比到大数值
func GetRateValue(rate int8) int64 {
return int64(float64(float32(rate)/float32(100)) * float64(PercentageRateValueMax))
}
// 大数值映射到百分比
func GetRate(rateValue int64) int8 {
return int8((float64(rateValue) / float64(PercentageRateValueMax)) * float64(100))
}
// 比率值变动速率计算
func CalculateRateSpeed(tick int32, lhDistance int64) int32 {
return int32(float64(tick) * (float64(PercentageRateValueMax) / float64(lhDistance)))
}

View File

@ -1,52 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
)
var PsdQuery = ecs.NewQuery(filter.Contains(components.PsdStateComponent, components.PsdTagHandlerComponent))
const (
//屏蔽门完全关闭
PsdCellWholeCloseValue = PercentageRateValueMax
//屏蔽门完全打开
PsdCellWholeOpenValue = PercentageRateValueMin
)
type PsdSystem struct {
cellsQuery map[cstate.EntityTag]*ecs.Query
}
func NewPsdSystem() *PsdSystem {
return &PsdSystem{cellsQuery: make(map[cstate.EntityTag]*ecs.Query)}
}
// world 执行
func (me *PsdSystem) Update(world ecs.World) {
PsdQuery.Each(world, func(psdEntry *ecs.Entry) {
psdTag := components.PsdTagHandlerComponent.Get(psdEntry).Tag
psdCellQuery, ok := me.cellsQuery[psdTag]
if !ok {
psdCellQuery = ecs.NewQuery(filter.Contains(psdTag, components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent))
me.cellsQuery[psdTag] = psdCellQuery
}
//
var allCellClosed, allCellOpened bool = true, true
psdCellQuery.Each(world, func(psdCellEntry *ecs.Entry) {
psdCellRate := components.PercentageDeviceStateComponent.Get(psdCellEntry).Rate
if allCellClosed {
allCellClosed = psdCellRate == PsdCellWholeCloseValue
}
if allCellOpened {
allCellOpened = psdCellRate == PsdCellWholeOpenValue
}
})
//
psdState := components.PsdStateComponent.Get(psdEntry)
psdState.AllClosed = allCellClosed
psdState.AllOpened = allCellOpened
})
}

64
system/relay_system.go Normal file
View File

@ -0,0 +1,64 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
sysEvent "joylink.club/rtsssimulation/system/event"
)
// 继电器有两个线圈1-2,3-4
// 电流方向1->2,3->4或4->3,2->1时产生同向磁场
type RelayState struct {
//继电器是否吸合
//true-吸合
Xh bool
//true-进行吸合动作false-进行落下动作
needXh bool
}
// 继电器状态组件
var RelayStateComponent = ecs.NewComponentType[RelayState]()
// 继电器系统
type RelaySystem struct {
relayQuery *ecs.Query
}
// 继电器常量定义
const (
//JWXC-1700无极缓放继电器,缓放时间ms
JWXC_1700_RELEASE_TIME int64 = 300
//JWJXC-H125/80无极加强缓放继电器缓放时间ms
JWJXC_H125_80_RELEASE_TIME int64 = 300
//整流式缓放继电器缓放时间ms
JZXC_H18_RELEASE_TIME int64 = 300
//JPXC-1000偏极继电器缓放时间ms
JPXC_1000_RELEASE_TIME int64 = 500
)
func NewRelaySystem() *RelaySystem {
return &RelaySystem{
relayQuery: ecs.NewQuery(filter.Contains(EntityIdentityComponent, RelayStateComponent)),
}
}
// 继电器须要改变事件处理
var RelayNeedChangeEventProcessor = func(w ecs.World, event sysEvent.RelayNeedChangeEvent) {
relayEntry := FindEntityById(w, event.Id)
relayState := RelayStateComponent.Get(relayEntry)
relayState.needXh = event.Xh
}
// world 执行
func (me *RelaySystem) Update(w ecs.World) {
me.relayQuery.Each(w, func(e *ecs.Entry) {
relayState := RelayStateComponent.Get(e)
//实际与目标不符,须动作
if relayState.needXh != relayState.Xh {
relayState.Xh = relayState.needXh
//发送动作事件
relayId := EntityIdentityComponent.Get(e).Id
sysEvent.RelayActionEventBus.Publish(w, &sysEvent.RelayActionEvent{Id: relayId, Xh: relayState.Xh})
}
})
}

View File

@ -0,0 +1,192 @@
package system
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
sysEvent "joylink.club/rtsssimulation/system/event"
"joylink.club/rtsssimulation/umi"
)
// 信号机电路继电器组合类型和功能名称常量
// 其他信号机的一并定义于此
const (
//继电器组合类型
SIGNAL_3XH1 = "3XH-1"
SIGNAL_3XH2 = "3XH-2"
SIGNAL_3XH3 = "3XH-3"
SIGNAL_3XH4 = "3XH-4"
SIGNAL_2XH1 = "2XH-1"
//继电器功能名称
SIGNAL_DDJ = "DDJ"
SIGNAL_DJ = "DJ"
SIGNAL_2DJ = "2DJ"
SIGNAL_LXJ = "LXJ"
SIGNAL_YXJ = "YXJ"
SIGNAL_ZXJ = "ZXJ"
)
// 电路状态信号机3XH-1(红-绿-黄) 道岔防护信号机(三显示不封灯,有单黄显示、带引导)
type Signal3XH1State struct {
// 物理黄灯true-亮
U bool
// 物理绿灯true-亮
L bool
// 物理红灯true-亮
H bool
// 点灯继电器true-吸合,常态落下表示逻辑点灯
DDJ bool
//2DJ灯丝继电器true-吸合
EDJ bool
//灯丝继电器true-吸合
DJ bool
//列车信号继电器true-吸合
LXJ bool
//引导信号继电器true-吸合
YXJ bool
//开通正线信号继电器true-吸合
ZXJ bool
}
func NewSignal3XH1State() *Signal3XH1State {
return &Signal3XH1State{
U: false,
L: false,
H: false,
DDJ: true,
EDJ: false,
DJ: false,
LXJ: false,
YXJ: false,
ZXJ: false,
}
}
// 信号机3XH-1电路状态组件
var Signal3XH1StateComponent = ecs.NewComponentType[Signal3XH1State]()
var signal3XH1Query = ecs.NewQuery(filter.Contains(EntityIdentityComponent, Signal3XH1StateComponent))
type Signal3XH1System struct {
}
func NewSignal3XH1System() *Signal3XH1System {
return &Signal3XH1System{}
}
// 继电器动作事件处理
// 将继电器动作的结果同步到系统
var Signal3XH1RelayActionEventProcessor = func(w ecs.World, event sysEvent.RelayActionEvent) {
//根据event来更新Signal3XH1State中对应继电器的状态
signal3XH1Query.Each(w, func(e *ecs.Entry) {
signalModel := FindModelStorage(w).FindById(EntityIdentityComponent.Get(e).Id)
roler, ok := signalModel.(umi.IRelayCRole)
if ok {
if relayGroup, relayName, find := roler.FindCircuitRoleById(event.Id); find {
if relayGroup == SIGNAL_3XH1 {
state := Signal3XH1StateComponent.Get(e)
switch relayName {
case SIGNAL_DDJ:
state.DDJ = event.Xh
case SIGNAL_DJ:
state.DJ = event.Xh
case SIGNAL_2DJ:
state.EDJ = event.Xh
case SIGNAL_LXJ:
state.LXJ = event.Xh
case SIGNAL_YXJ:
state.YXJ = event.Xh
case SIGNAL_ZXJ:
state.ZXJ = event.Xh
default:
panic(fmt.Sprintf("Signal3XH1的模型[%s]中继电器功能名称[%s]无法识别", signalModel.GetId(), relayName))
}
} else {
panic(fmt.Sprintf("Signal3XH1的模型[%s]中继电器组合类型[%s]无法识别", signalModel.GetId(), relayGroup))
}
}
} else {
panic("Signal3XH1的模型未实现接口umi.IRelayCRoler")
}
})
}
// world 执行
func (me *Signal3XH1System) Update(w ecs.World) {
signal3XH1Query.Each(w, func(e *ecs.Entry) {
signal3XH1State := Signal3XH1StateComponent.Get(e)
//
_U := signal3XH1State.U
_L := signal3XH1State.L
_H := signal3XH1State.H
//
me.calculateU(w, signal3XH1State)
me.calculateL(w, signal3XH1State)
me.calculateH(w, signal3XH1State)
me.calculateDJ(w, e, signal3XH1State)
me.calculate2DJ(w, e, signal3XH1State)
//状态改变发送事件
if _U != signal3XH1State.U || _H != signal3XH1State.H || _L != signal3XH1State.L {
signalId := EntityIdentityComponent.Get(e).Id
sysEvent.Signal3XH1AspectChangedEventBus.Publish(w, &sysEvent.Signal3XH1AspectChangedEvent{
Id: signalId,
U: signal3XH1State.U,
L: signal3XH1State.L,
H: signal3XH1State.H,
})
}
})
}
// 黄灯点灯电路
// 开放引导信号,黄灯亮且红灯亮
// 开放列车信号且开通侧向,只黄灯亮
func (me *Signal3XH1System) calculateU(w ecs.World, state *Signal3XH1State) {
//引导信号
isY := !state.DDJ && !state.LXJ && state.DJ && state.YXJ
//侧向行车信号
isLC := !state.DDJ && state.LXJ && !state.ZXJ
state.U = isY || isLC
}
// 绿灯点灯电路
// 开放正线行车信号,只亮绿灯
func (me *Signal3XH1System) calculateL(w ecs.World, state *Signal3XH1State) {
isL := !state.DDJ && state.LXJ && state.ZXJ
state.L = isL
}
// 红灯点灯电路
// 列车信号禁止时,亮红灯
func (me *Signal3XH1System) calculateH(w ecs.World, state *Signal3XH1State) {
isH := !state.DDJ && !state.LXJ
state.H = isH
}
// DJ 灯丝继电器电路
func (me *Signal3XH1System) calculateDJ(w ecs.World, e *ecs.Entry, state *Signal3XH1State) {
_DJ := state.DJ
//
isDj := !state.DDJ
//通知继电器进行动作
if _DJ != isDj {
signalModel := FindModelStorage(w).FindById(EntityIdentityComponent.Get(e).Id)
relayRole, _ := signalModel.(umi.IRelayCRole)
relayModel := relayRole.FindRelayModelByCRole(SIGNAL_3XH1, SIGNAL_DJ)
sysEvent.RelayNeedChangeEventBus.Publish(w, &sysEvent.RelayNeedChangeEvent{Id: relayModel.(umi.IDeviceModel).GetId(), Xh: isDj})
}
}
// 2DJ 灯丝继电器电路
func (me *Signal3XH1System) calculate2DJ(w ecs.World, e *ecs.Entry, state *Signal3XH1State) {
_2DJ := state.EDJ
//
is2DJ := state.U
//通知继电器进行动作
if _2DJ != is2DJ {
signalModel := FindModelStorage(w).FindById(EntityIdentityComponent.Get(e).Id)
relayRole, _ := signalModel.(umi.IRelayCRole)
relayModel := relayRole.FindRelayModelByCRole(SIGNAL_3XH1, SIGNAL_2DJ)
sysEvent.RelayNeedChangeEventBus.Publish(w, &sysEvent.RelayNeedChangeEvent{Id: relayModel.(umi.IDeviceModel).GetId(), Xh: is2DJ})
}
}

View File

@ -0,0 +1,793 @@
package system
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
sysEvent "joylink.club/rtsssimulation/system/event"
"joylink.club/rtsssimulation/umi"
)
// 双机ZDJ9道岔电路系统状态定义
// 继电器: true-吸合false-未吸合
type Switch2jZdj9State struct {
//定操继电器
DCJ bool
//反操继电器
FCJ bool
//允许操作继电器
YCJ bool
//总定表继电器
ZDBJ bool
//总反表继电器
ZFBJ bool
//道岔第一启动继电器
J1_1DQJ bool
//道岔保护继电器
J1_BHJ bool
//道岔第二启动继电器
//true-吸起即1-3通false-打落即1-2通
J1_2DQJ bool
//true-2DQJ由落下转换到吸起即定操
J1_2DQJ_ToD bool
//true-2DQJ由吸起转换到落下即反操
J1_2DQJ_ToF bool
//道岔第一启动继电器复示继电器
J1_1DQJF bool
//断相保护器
J1_DBQ DBQState
//定位表示继电器
J1_DBJ bool
//true-当道岔转换到定位时转辙机内端子9与电路接通false-转辙机内端子9断开切断电路
J1_DB_K9 bool
//转辙机内部自动开闭器
//true-接通1、3排表示电路,用于定操;false-接通2、4排表示电路用于反操
J1_AKB bool
//道岔电机1的电源
J1_Power Switch380ACPower
//电机线圈相电流
J1_U1 Switch380ACPhase
J1_V1 Switch380ACPhase
J1_W1 Switch380ACPhase
//电机输出牵引力大于0表示正转即定操小于0表示反转即反操等于0表示不转
J1_Traction int8
//反位表示继电器
J1_FBJ bool
//true-当道岔转换到反位时转辙机内端子10与电路接通false-转辙机内端子10断开切断电路
J1_FB_K10 bool
//道岔启动切断继电器
J1_QDJ bool
//道岔启动切断继电器的LC震荡电路保磁剩余时间,单位ms
//最长保持时长3000ms
J1_QDJ_LcTime int64
//总保护继电器
J1_ZBHJ bool
//道岔第一启动继电器
J2_1DQJ bool
//道岔保护继电器
J2_BHJ bool
//道岔第二启动继电器
//true-吸起即1-3通false-打落即1-2通
J2_2DQJ bool
//true-2DQJ由落下转换到吸起即定操
J2_2DQJ_ToD bool
//true-2DQJ由吸起转换到落下即反操
J2_2DQJ_ToF bool
//道岔第一启动继电器复示继电器
J2_1DQJF bool
//断相保护器
J2_DBQ DBQState
//定位表示继电器
J2_DBJ bool
//true-当道岔转换到定位时转辙机内端子9与电路接通false-转辙机内端子9断开切断电路
J2_DB_K9 bool
//反位表示继电器
J2_FBJ bool
//true-当道岔转换到反位时转辙机内端子10与电路接通false-转辙机内端子10断开切断电路
J2_FB_K10 bool
//转辙机内部自动开闭器
//true-接通1、3排表示电路,用于定操;false-接通2、4排表示电路用于反操
J2_AKB bool
//道岔电机2的电源
J2_Power Switch380ACPower
//电机线圈相电流
J2_U1 Switch380ACPhase
J2_V1 Switch380ACPhase
J2_W1 Switch380ACPhase
//电机转速大于0表示正转即定操小于0表示反转即反操等于0表示不转
J2_Traction int8
}
// 创建ZDJ9道岔状态并初始化
func NewSwitch2jZdj9State() *Switch2jZdj9State {
return &Switch2jZdj9State{
DCJ: false,
FCJ: false,
YCJ: false,
ZDBJ: true,
ZFBJ: false,
J1_1DQJ: false,
J1_BHJ: false,
J1_2DQJ: true,
J1_2DQJ_ToD: false,
J1_2DQJ_ToF: false,
J1_1DQJF: false,
J1_DBQ: DBQState{PhaseLoss: true, LimitedTime: 0, Dc24Voltage: false},
J1_DBJ: true,
J1_DB_K9: true,
J1_AKB: true,
J1_Power: Switch380ACPower{Active: false, PhaseA: false, PhaseB: false, PhaseC: false},
J1_U1: ACPahseN,
J1_V1: ACPahseN,
J1_W1: ACPahseN,
J1_Traction: 0,
J1_FBJ: false,
J1_FB_K10: false,
J1_QDJ: true,
J1_QDJ_LcTime: 0,
J1_ZBHJ: false,
J2_1DQJ: false,
J2_BHJ: false,
J2_2DQJ: true,
J2_2DQJ_ToD: false,
J2_2DQJ_ToF: false,
J2_1DQJF: false,
J2_DBQ: DBQState{PhaseLoss: true, LimitedTime: 0, Dc24Voltage: false},
J2_DBJ: true,
J2_DB_K9: true,
J2_FBJ: false,
J2_FB_K10: false,
J2_AKB: true,
J2_Power: Switch380ACPower{Active: false, PhaseA: false, PhaseB: false, PhaseC: false},
J2_U1: ACPahseN,
J2_V1: ACPahseN,
J2_W1: ACPahseN,
J2_Traction: 0,
}
}
// 带限时功能断相保护器
// 限时13秒
type DBQState struct {
//是否缺相true-缺相false-三相电正常未缺相
PhaseLoss bool
//剩余限时时间,单位ms
LimitedTime int64
//当三相电正常时断相保护器内的24V直流整流电路会正常输出24V直流电
//当三相电不正常如缺相时断相保护器内的24V直流整流电路不会输出24V直流电
//BHJ道岔保护继电器的励磁线圈由该24V直流供电
Dc24Voltage bool
}
// 表示电路变压器变压比2:1将220V交流电变压后作为为道岔表示电路的电源
// 0-无电源规定52端子为正1-输出瞬时正电压;-1 - 输出瞬时负电压
type SwitchBB struct {
//true-变压器初级输入正常
InDj220V bool
//次级输出电压
//0-无电源规定52端子为正1-输出瞬时正电压;-1 - 输出瞬时负电压
OutBb int8
}
// 道岔380V动力交流电源
type Switch380ACPower struct {
//true-激活
Active bool
//true-A相电正常输出
PhaseA bool
//true-B相电正常输出
PhaseB bool
//true-C相电正常输出
PhaseC bool
}
// 道岔380V动力交流电相位定义
type Switch380ACPhase int8
const (
//不存在相位交流电
ACPahseN Switch380ACPhase = iota
//存在A相位交流电
ACPahseA
//存在B相位交流电
ACPahseB
//存在C相位交流电
ACPahseC
)
// 继电器常量定义
const (
//QDJ 电源切断继电器LC震荡电路有效震荡时间ms
QDJ_LC_TIME int64 = 3000
//断相保护器限时单位ms
DBQ_LIMITED_TIME = 13 * 1000
)
// 道岔ZDJ9电路状态组件
var Switch2jZdj9StateComponent = ecs.NewComponentType[Switch2jZdj9State]()
// zdj9查询
var zdj9Query = ecs.NewQuery(filter.Contains(EntityIdentityComponent, Switch2jZdj9StateComponent))
// 双机ZDJ9道岔系统
type Switch2jZdj9System struct {
}
// 双机ZDJ9道岔系统
func NewSwitch2jZdj9System() *Switch2jZdj9System {
return &Switch2jZdj9System{}
}
// world 执行
func (me *Switch2jZdj9System) Update(w ecs.World) {
zdj9Query.Each(w, func(e *ecs.Entry) {
zdj9State := Switch2jZdj9StateComponent.Get(e)
//电机电源
me.calculateJPower(w, e, zdj9State)
//断相保护器电路
me.calculateDBQ(w, e, zdj9State)
//断相保护继电器励磁电路
me.calculateBHJ(w, e, zdj9State)
//总保护继电器励磁电路
me.calculateZBHJ(w, e, zdj9State)
//道岔转换启动切断继电器励磁电路
me.calculateQDJ(w, e, zdj9State)
//道岔第一启动继电器励磁电路
me.calculate1DQJ(w, e, zdj9State)
//道岔第一启动继电器复示继电器励磁电路
me.calculate1DQJF(w, e, zdj9State)
//道岔第二启动继电器励磁电路
me.calculate2DQJ(w, e, zdj9State)
//转辙机内自动开闭器
me.calculateAKB(w, e, zdj9State)
//道岔转辙机定表反表继电器励磁电路
me.calculateDBJ(w, e, zdj9State)
me.calculateFBJ(w, e, zdj9State)
//总定表/总反表继电器励磁电路
me.calculateZDBJ(w, e, zdj9State)
me.calculateZFBJ(w, e, zdj9State)
//道岔转辙机内电机驱动电路
me.calculateMotor(w, e, zdj9State)
me.calculateMove(w, e, zdj9State)
me.calculateK9K10(w, e, zdj9State)
})
}
// SJZDJ9双机zdj9
const (
//继电器组合类型
SJZDJ9_TDC = "TDC"
SJZDJ9_TDFJ1 = "TDFJ1"
SJZDJ9_TDFJ2 = "TDFJ2"
//继电器功能名称
SJZDJ9_1DQJ = "1DQJ"
SJZDJ9_BHJ = "BHJ"
SJZDJ9_2DQJ = "2DQJ"
SJZDJ9_1DQJF = "1DQJF"
SJZDJ9_DBJ = "DBJ"
SJZDJ9_FBJ = "FBJ"
SJZDJ9_QDJ = "QDJ"
SJZDJ9_ZBHJ = "ZBHJ"
SJZDJ9_DCJ = "DCJ"
SJZDJ9_FCJ = "FCJ"
SJZDJ9_YCJ = "YCJ"
SJZDJ9_ZDBJ = "ZDBJ"
SJZDJ9_ZFBJ = "ZFBJ"
)
// 接收继电器动作事件
var Switch2jzdj9RelayActionEventProcessor = func(w ecs.World, event sysEvent.RelayActionEvent) {
zdj9Query.Each(w, func(e *ecs.Entry) {
switchModel := FindModelStorage(w).FindById(EntityIdentityComponent.Get(e).Id)
roler, ok := switchModel.(umi.IRelayCRole)
if ok {
if relayGroup, relayName, find := roler.FindCircuitRoleById(event.Id); find {
state := Switch2jZdj9StateComponent.Get(e)
switch relayGroup {
case SJZDJ9_TDC:
{
switch relayName {
case SJZDJ9_DCJ:
state.DCJ = event.Xh
case SJZDJ9_FCJ:
state.FCJ = event.Xh
case SJZDJ9_YCJ:
state.YCJ = event.Xh
case SJZDJ9_ZDBJ:
state.ZDBJ = event.Xh
case SJZDJ9_ZFBJ:
state.ZFBJ = event.Xh
default:
panic(fmt.Sprintf("SwitchZdj9的模型[%s]中继电器功能名称[%s]无法识别", switchModel.GetId(), relayName))
}
}
case SJZDJ9_TDFJ1:
{
switch relayName {
case SJZDJ9_1DQJ:
state.J1_1DQJ = event.Xh
case SJZDJ9_BHJ:
state.J1_BHJ = event.Xh
case SJZDJ9_2DQJ:
{
state.J1_2DQJ_ToD = !state.J1_2DQJ && event.Xh
state.J1_2DQJ_ToF = state.J1_2DQJ && !event.Xh
state.J1_2DQJ = event.Xh
}
case SJZDJ9_1DQJF:
state.J1_1DQJF = event.Xh
case SJZDJ9_DBJ:
state.J1_DBJ = event.Xh
case SJZDJ9_FBJ:
state.J1_FBJ = event.Xh
case SJZDJ9_QDJ:
state.J1_QDJ = event.Xh
case SJZDJ9_ZBHJ:
state.J1_ZBHJ = event.Xh
default:
panic(fmt.Sprintf("SwitchZdj9的模型[%s]中继电器功能名称[%s]无法识别", switchModel.GetId(), relayName))
}
}
case SJZDJ9_TDFJ2:
{
switch relayName {
case SJZDJ9_1DQJ:
state.J2_1DQJ = event.Xh
case SJZDJ9_BHJ:
state.J2_BHJ = event.Xh
case SJZDJ9_2DQJ:
{
state.J2_2DQJ_ToD = !state.J2_2DQJ && event.Xh
state.J2_2DQJ_ToF = state.J2_2DQJ && !event.Xh
state.J2_2DQJ = event.Xh
}
case SJZDJ9_1DQJF:
state.J2_1DQJF = event.Xh
case SJZDJ9_DBJ:
state.J2_DBJ = event.Xh
case SJZDJ9_FBJ:
state.J2_FBJ = event.Xh
default:
panic(fmt.Sprintf("SwitchZdj9的模型[%s]中继电器功能名称[%s]无法识别", switchModel.GetId(), relayName))
}
}
default:
panic(fmt.Sprintf("SwitchZdj9的模型[%s]中继电器组合类型[%s]无法识别", switchModel.GetId(), relayGroup))
}
}
} else {
panic("SwitchZdj9的模型未实现接口umi.IRelayCRoler")
}
})
}
// 发送继电器需要改变事件
func (me *Switch2jZdj9System) publishRelayNeedChangeEvent(w ecs.World, switchEntry *ecs.Entry, relayGroup string, relayName string, needXh bool) {
switchModel := FindModelStorage(w).FindById(EntityIdentityComponent.Get(switchEntry).Id)
relayRole, _ := switchModel.(umi.IRelayCRole)
relayModel := relayRole.FindRelayModelByCRole(relayGroup, relayName)
sysEvent.RelayNeedChangeEventBus.Publish(w, &sysEvent.RelayNeedChangeEvent{Id: relayModel.(umi.IDeviceModel).GetId(), Xh: needXh})
}
// 断相保护电路运算
func (me *Switch2jZdj9System) calculateDBQ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
if state.J1_DBQ.LimitedTime > 0 {
state.J1_DBQ.LimitedTime -= int64(w.Tick())
if state.J1_DBQ.LimitedTime < 0 {
state.J1_DBQ.LimitedTime = 0
}
}
//
state.J1_DBQ.PhaseLoss = !state.J1_Power.PhaseA || !state.J1_Power.PhaseB || !state.J1_Power.PhaseC
//
state.J1_DBQ.Dc24Voltage = !state.J1_DBQ.PhaseLoss
///////////////////////////////////////////////////
if state.J2_DBQ.LimitedTime > 0 {
state.J2_DBQ.LimitedTime -= int64(w.Tick())
if state.J2_DBQ.LimitedTime < 0 {
state.J2_DBQ.LimitedTime = 0
}
}
//
state.J2_DBQ.PhaseLoss = !state.J2_Power.PhaseA || !state.J2_Power.PhaseB || !state.J2_Power.PhaseC
//
state.J2_DBQ.Dc24Voltage = !state.J2_DBQ.PhaseLoss
}
// 转辙机内自动开闭器动作实现
// 暂时规定自动开闭器跟随2DQJ
func (me *Switch2jZdj9System) calculateAKB(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
state.J1_AKB = state.J1_2DQJ
state.J2_AKB = state.J2_2DQJ
}
// 断相保护继电器运算
// BHJ JWXC-1700无极缓放继电器
func (me *Switch2jZdj9System) calculateBHJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
_J1_BHJ := state.J1_DBQ.Dc24Voltage
_J2_BHJ := state.J2_DBQ.Dc24Voltage
if _J1_BHJ != state.J1_BHJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_BHJ, _J1_BHJ)
}
if _J2_BHJ != state.J2_BHJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ2, SJZDJ9_BHJ, _J2_BHJ)
}
}
// 总保护继电器运算
// ZBHJ JWXC-1700无极缓放继电器
func (me *Switch2jZdj9System) calculateZBHJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//励磁
method := state.J1_BHJ && state.J2_BHJ
//自闭
self := state.J1_ZBHJ && (state.J1_BHJ || state.J2_BHJ)
//
_J1_ZBHJ := method || self
//为总保护继电器励磁
if _J1_ZBHJ != state.J1_ZBHJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_ZBHJ, _J1_ZBHJ)
}
}
// 道岔转换启动切断继电器运算
// QDJ JWXC-1700无极缓放继电器
func (me *Switch2jZdj9System) calculateQDJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//LC震荡电路运算
fullLc := (!state.J1_BHJ && !state.J2_BHJ) || state.J1_ZBHJ
if fullLc {
state.J1_QDJ_LcTime = QDJ_LC_TIME
} else {
if state.J1_QDJ_LcTime > 0 {
state.J1_QDJ_LcTime -= int64(w.Tick())
if state.J1_QDJ_LcTime < 0 {
state.J1_QDJ_LcTime = 0
}
}
}
//自闭励磁电路
self := state.J1_QDJ && state.J1_ZBHJ
//为启动切断继电器励磁
_J1_QDJ := self || fullLc || state.J1_QDJ_LcTime > 0
if _J1_QDJ != state.J1_QDJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_QDJ, _J1_QDJ)
}
}
// 道岔第一启动继电器运算
// 1DQJ JWJXC-H125/80无极加强缓放继电器
// J1先启动J2后启动
func (me *Switch2jZdj9System) calculate1DQJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//自闭电路
j2DqjSelf := state.J1_QDJ && state.J2_BHJ && state.J2_1DQJ
//励磁电路
j2DqjMethod1 := state.YCJ && state.J1_1DQJ && (!state.J2_2DQJ && state.DCJ || state.J2_2DQJ && state.FCJ)
//
j2DqjIs := j2DqjMethod1 || j2DqjSelf
//为J2第一启动继电器励磁
if j2DqjIs != state.J2_1DQJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ2, SJZDJ9_1DQJ, j2DqjIs)
}
// ---------------
//励磁电路
j1DqjMethod1 := state.YCJ && (!state.J1_2DQJ && state.DCJ || state.J1_2DQJ && state.FCJ)
//自闭电路
j1DqjSelf := state.J1_QDJ && state.J1_BHJ && state.J1_1DQJ
//
j1DqjIs := j1DqjMethod1 || j1DqjSelf
//为J1第一启动继电器励磁
if j1DqjIs != state.J1_1DQJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_1DQJ, j1DqjIs)
}
}
// 道岔第一启动继电器复示继电器运算
// 1DQJF JWJXC-480无极继电器
func (me *Switch2jZdj9System) calculate1DQJF(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
_J1_1DQJF := state.J1_1DQJ
_J2_1DQJF := state.J2_1DQJ
if _J1_1DQJF != state.J1_1DQJF {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_1DQJF, _J1_1DQJF)
}
if _J2_1DQJF != state.J2_1DQJF {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ2, SJZDJ9_1DQJF, _J2_1DQJF)
}
}
// 道岔第二启动继电器运算
// 2DQJ JYJXC-160/260有极加强继电器
// 2DQJ为有极继电器根据线圈中电流极性不同具有 定位和反位 两种稳定状态,这两种稳定状态当线圈中电流消失时仍能继续保持;
// 在线圈中通以规定极性的电流时,继电器吸起,断电后仍保持在吸起位置;通以反方向电流时,继电器打落,断电后保持在打落位置;
// 断电保持由磁路系统中的一块长条形永久磁铁取代了大部分轭铁来实现;
// 电流3->4吸起电流2->1打落如果21和34同时通过电流时磁场相互抵消则继电器保持原来状态不变
func (me *Switch2jZdj9System) calculate2DQJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//J1-2DQJ
j1_2dqj_21 := state.J1_1DQJF && state.FCJ
j1_2dqj_34 := state.J1_1DQJF && state.DCJ
//磁通量,矢量
var j12dqj int8 = 0
if j1_2dqj_34 {
j12dqj++
}
if j1_2dqj_21 {
j12dqj--
}
if j12dqj != 0 {
_J1_2DQJ := j12dqj > 0
if _J1_2DQJ != state.J1_2DQJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_2DQJ, _J1_2DQJ)
}
}
//J2-2DQJ
j2_2dqj_21 := state.J2_1DQJF && state.FCJ
j2_2dqj_34 := state.J2_1DQJF && state.DCJ
//磁通量,矢量
var j22dqj int8 = 0
if j2_2dqj_34 {
j22dqj++
}
if j2_2dqj_21 {
j22dqj--
}
if j22dqj != 0 {
_J2_2DQJ := j22dqj > 0
if _J2_2DQJ != state.J2_2DQJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ2, SJZDJ9_2DQJ, _J2_2DQJ)
}
}
}
// 道岔总定表继电器运算
// ZDBJ JPXC-1000 偏极继电器是为了鉴别信号电路中的电流极性而设计
// 继电器在磁路中增加一个偏极磁钢,使衔铁受永磁力的作用而偏于落下位置。衔铁的吸起与线圈中的电流的极性有关,
// 通过线圈的电流为规定的方向时,衔铁才吸起,而电流的方向相反时,衔铁保持不动。
// 它只具有一种稳定状态,即衔铁靠电磁力吸起后,断电即落下,始终偏向落下的定位状态
func (me *Switch2jZdj9System) calculateZDBJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
_ZDBJ := state.J1_DBJ && state.J2_DBJ
if _ZDBJ != state.ZDBJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDC, SJZDJ9_ZDBJ, _ZDBJ)
}
}
func (me *Switch2jZdj9System) calculateZFBJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
_ZFBJ := state.J1_FBJ && state.J2_FBJ
if _ZFBJ != state.ZFBJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDC, SJZDJ9_ZFBJ, _ZFBJ)
}
}
// 道岔定表继电器运算
// DBJ JPXC-1000 偏极继电器
// BB的负半周期提供DBJ的励磁电流
func (me *Switch2jZdj9System) calculateDBJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//j1 DBJ励磁
j1DbjLc := state.J1_2DQJ && state.J1_AKB && state.J1_DB_K9 && !state.J1_1DQJ
if j1DbjLc != state.J1_DBJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_DBJ, j1DbjLc)
}
//j2 DBJ励磁
j2DbjLc := state.J2_2DQJ && state.J2_AKB && state.J2_DB_K9 && !state.J2_1DQJ
if j2DbjLc != state.J2_DBJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ2, SJZDJ9_DBJ, j2DbjLc)
}
}
// 道岔反表继电器运算
// FBJ JPXC-1000 偏极继电器
// BB的正半周期提供FBJ的励磁流
func (me *Switch2jZdj9System) calculateFBJ(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//j1 FBJ励磁
j1FbjLc := !state.J1_2DQJ && !state.J1_AKB && state.J1_FB_K10 && !state.J1_1DQJ
if j1FbjLc != state.J1_FBJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ1, SJZDJ9_FBJ, j1FbjLc)
}
//j2
j2FbjLc := !state.J2_2DQJ && !state.J2_AKB && state.J2_FB_K10 && !state.J2_1DQJ
if j2FbjLc != state.J2_FBJ {
me.publishRelayNeedChangeEvent(w, switchEntry, SJZDJ9_TDFJ2, SJZDJ9_FBJ, j2FbjLc)
}
}
// 道岔转动运算
// j1 完全转动须4000ms
// j2 完全转动须5000ms
const (
J1Range int64 = 4000
J2Range int64 = 5000
)
// 道岔转动运算
// j1 完全转动须4000ms
// j2 完全转动须5000ms
// j.Value 0-反位 jRange-定位
func (me *Switch2jZdj9System) calculateMove(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
j1 := MovableObject1Component.Get(switchEntry)
//
if j1.Value < 0 {
j1.Value = 0
} else if j1.Value > J1Range {
j1.Value = J1Range
}
j1.direction = state.J1_Traction
//
j2 := MovableObject2Component.Get(switchEntry)
//
if j2.Value < 0 {
j2.Value = 0
} else if j2.Value > J2Range {
j2.Value = J2Range
}
j2.direction = state.J2_Traction
}
// 转辙机对外端子9、10运算
func (me *Switch2jZdj9System) calculateK9K10(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
j1 := MovableObject1Component.Get(switchEntry)
j2 := MovableObject2Component.Get(switchEntry)
//
state.J1_DB_K9 = j1.Value >= J1Range
state.J1_FB_K10 = j1.Value <= 0
//
state.J2_DB_K9 = j2.Value >= J2Range
state.J2_FB_K10 = j2.Value <= 0
}
// 转辙机电源控制
// 1DQj启动继电器吸合时接通电源
func (me *Switch2jZdj9System) calculateJPower(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//超时断电
j1csdd := state.J1_Power.Active && state.J1_DBQ.LimitedTime <= 0
//转换到位断电
j1zhdwdd := state.J1_2DQJ_ToD && state.J1_DB_K9 || state.J1_2DQJ_ToF && state.J1_FB_K10
if j1csdd || j1zhdwdd {
state.J1_Power.PhaseA = false
state.J1_Power.PhaseB = false
state.J1_Power.PhaseC = false
state.J1_2DQJ_ToD = false
state.J1_2DQJ_ToF = false
}
//第一启动继电器落下
if !state.J1_1DQJ {
state.J1_Power.Active = false
}
//接通电源
if state.J1_1DQJ && !state.J1_Power.Active {
state.J1_Power.Active = true
state.J1_Power.PhaseA = true
state.J1_Power.PhaseB = true
state.J1_Power.PhaseC = true
state.J1_DBQ.LimitedTime = DBQ_LIMITED_TIME
}
//----------------
//超时断电
j2csdd := state.J2_Power.Active && state.J2_DBQ.LimitedTime <= 0
//转换到位断电
j2zhdwdd := state.J2_2DQJ_ToD && state.J2_DB_K9 || state.J2_2DQJ_ToF && state.J2_FB_K10
if j2csdd || j2zhdwdd {
state.J2_Power.PhaseA = false
state.J2_Power.PhaseB = false
state.J2_Power.PhaseC = false
state.J2_2DQJ_ToD = false
state.J2_2DQJ_ToF = false
}
//第一启动继电器落下
if !state.J2_1DQJ {
state.J2_Power.Active = false
}
//接通电源
if state.J2_1DQJ && !state.J2_Power.Active {
state.J2_Power.Active = true
state.J2_Power.PhaseA = true
state.J2_Power.PhaseB = true
state.J2_Power.PhaseC = true
state.J2_DBQ.LimitedTime = DBQ_LIMITED_TIME
}
}
// 道岔转辙机电机内线圈电路运算
// ABC三相电电机线圈UVW,
// 定位到反位U-A V-C W-B 即U->W->V电机反转反操接通2、4排表示电路
// 反位到定位U-A V-B W-C 即U->V->W电机正转定操接通1、3排表示电路
func (me *Switch2jZdj9System) calculateMotor(w ecs.World, switchEntry *ecs.Entry, state *Switch2jZdj9State) {
//电机1
state.J1_U1 = ACPahseN
state.J1_V1 = ACPahseN
state.J1_W1 = ACPahseN
state.J1_Traction = 0
//A相电
if state.J1_Power.PhaseA && state.J1_1DQJ {
state.J1_U1 = ACPahseA
}
//B相电
if state.J1_Power.PhaseB && state.J1_1DQJF {
if state.J1_2DQJ {
if state.J1_AKB {
state.J1_V1 = ACPahseB
}
} else {
if !state.J1_AKB {
state.J1_W1 = ACPahseB
}
}
}
//C相电
if state.J1_Power.PhaseC && state.J1_1DQJF {
if state.J1_2DQJ {
if state.J1_AKB {
state.J1_W1 = ACPahseC
}
} else {
if !state.J1_AKB {
state.J1_V1 = ACPahseC
}
}
}
//牵引力
if state.J1_U1 == ACPahseA {
switch {
case state.J1_V1 == ACPahseB: //U-A V-B W-C
{
if state.J1_W1 == ACPahseC {
state.J1_Traction = 1
}
}
case state.J1_V1 == ACPahseC: //U-A W-B V-C
{
if state.J1_W1 == ACPahseB {
state.J1_Traction = -1
}
}
}
}
/////////////
//电机2
state.J2_U1 = ACPahseN
state.J2_V1 = ACPahseN
state.J2_W1 = ACPahseN
state.J2_Traction = 0
//A相电
if state.J2_Power.PhaseA && state.J2_1DQJ {
state.J2_U1 = ACPahseA
}
//B相电
if state.J2_Power.PhaseB && state.J2_1DQJF {
if state.J2_2DQJ {
if state.J2_AKB {
state.J2_V1 = ACPahseB
}
} else {
if !state.J2_AKB {
state.J2_W1 = ACPahseB
}
}
}
//C相电
if state.J2_Power.PhaseC && state.J2_1DQJF {
if state.J2_2DQJ {
if state.J2_AKB {
state.J2_W1 = ACPahseC
}
} else {
if !state.J2_AKB {
state.J2_V1 = ACPahseC
}
}
}
//牵引力
if state.J2_U1 == ACPahseA {
switch {
case state.J2_V1 == ACPahseB: //U-A V-B W-C
{
if state.J2_W1 == ACPahseC {
state.J2_Traction = 1
}
}
case state.J2_V1 == ACPahseC: //U-A W-B V-C
{
if state.J2_W1 == ACPahseB {
state.J2_Traction = -1
}
}
}
}
}

View File

@ -1,68 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/umi"
)
var SwitchQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.SwitchRelayStateComponent, components.PercentageDeviceStateComponent))
const (
//道岔定位
SwitchNormalVaule int64 = PercentageRateValueMin
//道岔反位
SwitchReverseValue int64 = PercentageRateValueMax
)
// 道岔系统操作
type SwitchSystem struct {
}
func NewSwitchSystem() *SwitchSystem {
return &SwitchSystem{}
}
// world 执行
func (me *SwitchSystem) Update(w ecs.World) {
//根据定操反操继电器来设置道岔转动参数
SwitchQuery.Each(w, func(e *ecs.Entry) {
relay := components.SwitchRelayStateComponent.Get(e)
if relay.DcJ || relay.FcJ {
movable := components.MovableDeviceStateComponent.Get(e)
percent := components.PercentageDeviceStateComponent.Get(e)
switchId := components.DeviceIdentityComponent.Get(e).Id
if relay.DcJ {
movable.ToH = false
percent.Target = SwitchNormalVaule
}
if relay.FcJ {
movable.ToH = true
percent.Target = SwitchReverseValue
}
movable.Speed = CalculateRateSpeed(int32(w.Tick()), getSwitchTurnTime(w, switchId))
}
})
//观察道岔百分比组件来更新道岔逻辑继电器状态
SwitchQuery.Each(w, func(e *ecs.Entry) {
switchPercent := components.PercentageDeviceStateComponent.Get(e)
switchRelay := components.SwitchRelayStateComponent.Get(e)
if switchPercent.Rate == switchPercent.Target {
switchRelay.DcJ = false
switchRelay.FcJ = false
switchRelay.DbJ = switchPercent.Rate <= SwitchNormalVaule
switchRelay.FbJ = switchPercent.Rate >= SwitchReverseValue
} else {
switchRelay.DbJ = false
switchRelay.FbJ = false
}
})
}
// 获取道岔转动耗时ms
func getSwitchTurnTime(world ecs.World, switchId string) int64 {
dcModel := WorldModelStorage(world).FindById(switchId)
var dc umi.ISwitchModel = dcModel.(umi.ISwitchModel)
return dc.TurningTime()
}

View File

@ -1,165 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
)
// 继电器: true-吸合false-未吸合
type SwitchZdj9State struct {
//定操继电器
DCJ bool
//反操继电器
FCJ bool
//允许操作继电器
YCJ bool
//总定表继电器
ZDBJ bool
//总反表继电器
ZFBJ bool
//表示电路变压器将220V交流电变压后作为为道岔表示电路的电源
//0-无电源规定52端子为正1-输出瞬时正电压;-1 - 输出瞬时负电压
J1_BB int8
//道岔第一启动继电器
J1_1DQJ bool
//道岔保护继电器
J1_BHJ bool
//道岔第二启动继电器
J1_2DQJ bool
//道岔第一启动继电器复示继电器
J1_1DQJF bool
//断相保护器
J1_DBQ DBQState
//定位表示继电器
J1_DBJ bool
//反位表示继电器
J1_FBJ bool
//道岔启动切断继电器
J1_QDJ bool
//道岔启动切断继电器的LC震荡电路保磁剩余时间,单位ms
//最长保持时长3000ms
J1_QDJ_LcTime int64
//总保护继电器
J1_ZBHJ bool
//表示电路变压器将220V交流电变压后作为为道岔表示电路的电源
//0-无电源规定52端子为正1-输出瞬时正电压;-1 - 输出瞬时负电压
J2_BB int8
//道岔第一启动继电器
J2_1DQJ bool
//道岔保护继电器
J2_BHJ bool
//道岔第二启动继电器
J2_2DQJ bool
//道岔第一启动继电器复示继电器
J2_1DQJF bool
//断相保护器
J2_DBQ DBQState
//定位表示继电器
J2_DBJ bool
//反位表示继电器
J2_FBJ bool
}
// 带限时功能断相保护器
// 限时13秒
type DBQState struct {
//是否缺相true-缺相false-三相电正常未缺相
PhaseLoss bool
//剩余限时时间,单位ms
LimitedTime int64
//当三相电正常时断相保护器内的24V直流整流电路会正常输出24V直流电
//当三相电不正常如缺相时断相保护器内的24V直流整流电路不会输出24V直流电
//BHJ道岔保护继电器的励磁线圈由该24V直流供电
Dc24Voltage bool
}
// 道岔ZDJ9电路状态组件
var SwitchZdj9StateComponent = ecs.NewComponentType[SwitchZdj9State]()
// ZDJ9道岔系统
type SwitchZdj9System struct {
zdj9Query *ecs.Query
}
func NewSwitchZdj9System() *SwitchZdj9System {
return &SwitchZdj9System{zdj9Query: ecs.NewQuery(filter.Contains(SwitchZdj9StateComponent))}
}
// world 执行
func (me *SwitchZdj9System) Update(w ecs.World) {
me.zdj9Query.Each(w, func(e *ecs.Entry) {
zdj9State := SwitchZdj9StateComponent.Get(e)
//断相保护器电路
calculateDBQ(w, zdj9State)
//断相保护继电器励磁电路
calculateBHJ(w, zdj9State)
//总保护继电器励磁电路
calculateZBHJ(w, zdj9State)
//道岔转换启动切断继电器励磁电路
calculateQDJ(w, zdj9State)
//道岔一次启动继电器励磁电路
calculateDQJ(w, zdj9State)
})
}
// 断相保护电路运算
func calculateDBQ(w ecs.World, state *SwitchZdj9State) {
if state.J1_DBQ.LimitedTime > 0 {
state.J1_DBQ.LimitedTime -= int64(w.Tick())
} else {
state.J1_DBQ.LimitedTime = 0
}
state.J1_DBQ.Dc24Voltage = !state.J1_DBQ.PhaseLoss
//
if state.J2_DBQ.LimitedTime > 0 {
state.J2_DBQ.LimitedTime -= int64(w.Tick())
} else {
state.J2_DBQ.LimitedTime = 0
}
state.J2_DBQ.Dc24Voltage = !state.J2_DBQ.PhaseLoss
}
// 断相保护继电器运算
func calculateBHJ(w ecs.World, state *SwitchZdj9State) {
state.J1_BHJ = state.J1_DBQ.Dc24Voltage
state.J2_BHJ = state.J2_DBQ.Dc24Voltage
}
// 总保护继电器运算
func calculateZBHJ(w ecs.World, state *SwitchZdj9State) {
//励磁
method1 := state.J1_BHJ && state.J2_BHJ
//励磁
method2 := state.J1_ZBHJ && (state.J1_BHJ || state.J2_BHJ)
//为总保护继电器励磁
state.J1_ZBHJ = method1 || method2
}
// 道岔转换启动切断继电器运算
func calculateQDJ(w ecs.World, state *SwitchZdj9State) {
//LC震荡电路运算
fullLc := (!state.J1_BHJ && !state.J2_BHJ) || state.J1_ZBHJ
if fullLc {
state.J1_QDJ_LcTime = 3000
} else {
state.J1_QDJ_LcTime -= int64(w.Tick())
if state.J1_QDJ_LcTime < 0 {
state.J1_QDJ_LcTime = 0
}
}
//自闭励磁电路
self := state.J1_QDJ && state.J1_ZBHJ
//为启动切断继电器励磁
state.J1_QDJ = self || fullLc || state.J1_QDJ_LcTime > 0
}
// 道岔第一启动继电器运算
func calculateDQJ(w ecs.World, state *SwitchZdj9State) {
//励磁电路
j1DqjMethod1 := state.YCJ && (state.DCJ || state.FCJ)
//自闭电路
j1DqjSelf := state.J1_QDJ && state.J1_BHJ && state.J1_1DQJ
//为J1第一启动继电器励磁
state.J1_1DQJ = j1DqjMethod1 || j1DqjSelf
}

View File

@ -3,14 +3,22 @@ package system
import (
"fmt"
"github.com/yohamta/donburi/component"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/umi"
)
// 实体身份定义
type EntityIdentity struct {
Id string
}
// 实体身份组件
var EntityIdentityComponent = ecs.NewComponentType[EntityIdentity]()
func FindEntityById(world ecs.World, id string) *ecs.Entry {
query := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent))
query := ecs.NewQuery(filter.Contains(EntityIdentityComponent))
return QueryEntityById(world, query, id)
}
func QueryEntityById(world ecs.World, q *ecs.Query, id string) *ecs.Entry {
@ -18,7 +26,7 @@ func QueryEntityById(world ecs.World, q *ecs.Query, id string) *ecs.Entry {
func() {
defer simpleRecover()
q.Each(world, func(e *ecs.Entry) {
if id == components.DeviceIdentityComponent.Get(e).Id {
if id == EntityIdentityComponent.Get(e).Id {
entry = e
panic(fmt.Sprintf("找到实体[%s],结束查找", id))
}
@ -28,38 +36,35 @@ func QueryEntityById(world ecs.World, q *ecs.Query, id string) *ecs.Entry {
return entry
}
var modelStorageQuery = ecs.NewQuery(filter.Contains(ModelStorageComponent))
// 获取模型仓库
func FindModelStorage(world ecs.World) umi.IModelManager {
e, _ := modelStorageQuery.First(world)
return ModelStorageComponent.Get(e).ModelManager
}
// 捕获panic并恢复执行
func simpleRecover() {
recover()
}
// /////////////////////////////////////////////////////////////////////////
// 模型仓库查询
var worldModelStorageQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.ModelStorageRefComponent))
/////////////////////////////////////////////////////////
func WorldModelStorage(world ecs.World) umi.IModelManager {
e, ok := worldModelStorageQuery.First(world)
if ok {
return components.ModelStorageRefComponent.Get(e).ModelManager
} else {
return nil
}
// 实体标签
type EntityTag = component.IComponentType
type EntityTagHandler struct {
Tag EntityTag
}
// //////////////////////////////////////////////////////////////////////////
// 继电器系统
type relaySystem struct {
// key-设备id
relayQuery map[string]*ecs.Query
/////////////////////////////////////////////////////////
// 模型仓库引用
// 用于world内使用查询模型
type ModelStorageRef struct {
ModelManager umi.IModelManager
}
// 获取设备的相关继电器的查询
func (me *relaySystem) getDeviceRelayQuery(deviceEntry *ecs.Entry) *ecs.Query {
id := components.DeviceIdentityComponent.Get(deviceEntry).Id
query, ok := me.relayQuery[id]
if !ok {
query = ecs.NewQuery(filter.Contains(components.RelayTagHandlerComponent.Get(deviceEntry).Tag))
me.relayQuery[id] = query
}
return query
}
// 模型仓库组件
var ModelStorageComponent = ecs.NewComponentType[ModelStorageRef]()

View File

@ -5,10 +5,11 @@ import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
var timerQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.SystemTimerComponent))
var SystemTimerComponent = ecs.NewComponentType[SystemTimer]()
var timerQuery *ecs.Query = ecs.NewQuery(filter.Contains(SystemTimerComponent))
// 系统时钟操作
type TimerSystem struct {
@ -21,7 +22,7 @@ func NewTimerSystem() *TimerSystem {
// world 执行
func (me *TimerSystem) Update(w ecs.World) {
if e, ok := timerQuery.First(w); ok {
timer := components.SystemTimerComponent.Get(e)
timer := SystemTimerComponent.Get(e)
timer.Tick(w.Tick())
}
}
@ -29,7 +30,7 @@ func (me *TimerSystem) Update(w ecs.World) {
// 重置world时间
func ResetWorldTimer(w ecs.World, time time.Time) {
if e, ok := timerQuery.First(w); ok {
timer := components.SystemTimerComponent.Get(e)
timer := SystemTimerComponent.Get(e)
timer.ResetTime(time)
}
}
@ -37,9 +38,38 @@ func ResetWorldTimer(w ecs.World, time time.Time) {
// 获取world当前时间
func GetWorldNow(w ecs.World) *time.Time {
if e, ok := timerQuery.First(w); ok {
timer := components.SystemTimerComponent.Get(e)
timer := SystemTimerComponent.Get(e)
now := timer.Now()
return &now
}
return nil
}
/////////////////////////////////////////////////////////////////
// 系统时钟,单例
type SystemTimer struct {
timer *time.Time
}
// 以指定时间构建
func NewSystemTimer(time *time.Time) *SystemTimer {
return &SystemTimer{
timer: time,
}
}
// 重置时间
func (me *SystemTimer) ResetTime(time time.Time) {
*me.timer = time
}
// 获取当前时间的副本
func (me *SystemTimer) Now() time.Time {
return *me.timer
}
// tick系统时钟,单位ms
func (me *SystemTimer) Tick(tick int) {
*me.timer = me.timer.Add(time.Duration(tick) * time.Millisecond)
}

View File

@ -82,8 +82,6 @@ type ILinkOffsetRef interface {
// 仿真底层道岔模型
// 用户所有道岔模型定义须实现该接口
type ISwitchModel interface {
//道岔转动从0-100耗时单位ms
TurningTime() int64
//道岔A端口连接的轨道
PortALink() ILinkRef
//道岔B端口连接的轨道
@ -110,17 +108,51 @@ type IPsdModel interface {
}
////////////////////////////////////////////////////////////
//继电器类型定义
type RelayType = int8
//继电器类枚举
const (
//无极缓放继电器
JWXC_1700 RelayType = iota + 1
//
JWXC_H340
//偏极继电器是为了鉴别信号电路中的电流极性而设计
//继电器在磁路中增加一个偏极磁钢,使衔铁受永磁力的作用而偏于落下位置。衔铁的吸起与线圈中的电流的极性有关,
//通过线圈的电流为规定的方向时,衔铁才吸起,而电流的方向相反时,衔铁保持不动。
//它只具有一种稳定状态,即衔铁靠电磁力吸起后,断电即落下,始终偏向落下的定位状态
JPXC_1000
//无极加强缓放继电器
JWJXC_H125_80
//有极加强继电器
//根据线圈中电流极性不同具有 定位和反位 两种稳定状态,这两种稳定状态当线圈中电流消失时仍能继续保持;
//在线圈中通以规定极性的电流时,继电器吸起,断电后仍保持在吸起位置;通以反方向电流时,继电器打落,断电后保持在打落位置;
//断电保持由磁路系统中的一块长条形永久磁铁取代了大部分轭铁来实现即断电保持当前状态
JYJXC_160_260
//无极继电器
JWJXC_480
//整流式缓放继电器
JZXC_H18
)
// 继电器模型
// 继电器按作用分类:驱动继电器、采集继电器
type IRelayModel interface {
//该继电器管理的设备
ManagedDevice() IDeviceModel
//true-驱动继电器false-采集继电器
IsDriver() bool
//继电器作用名称,同一个设备的继电器的作用名称不能重复
//如DJ-12、DDJ-83
UsageName() string
//该继电器类型
JType() RelayType
}
/////////////////////////////////////////////////////////////
// 获取继电器在具体电路中的角色(组合类型、功能名称)
// 如信号机3XH-1电路中点灯继电器组合类型-"3XH-1" 功能名称-"DDJ"
// 对应设备电路中有继电器的设备模型须实现该接口
type IRelayCRole interface {
//根据继电器id获取在具体电路中的电路角色
//relayId-继电器id
//relayGroup-继电器组合类型
//relayName-继电器在电路中的名称
//find-true找到false未找到
FindCircuitRoleById(relayId string) (relayGroup string, relayName string, find bool)
//根据继电器具体电路角色来获取继电器设备模型
//relayGroup-继电器组合类型
//relayName-继电器在电路中的名称
FindRelayModelByCRole(relayGroup string, relayName string) IRelayModel
}