rts-sim-module/sys/iscs_sys/iscs_bas_fluid.go

294 lines
9.7 KiB
Go
Raw Normal View History

2023-12-27 18:11:27 +08:00
package iscs_sys
import (
"fmt"
"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"
2023-12-29 17:00:26 +08:00
"log/slog"
2023-12-27 18:11:27 +08:00
)
// FluidDriverSystem 流体驱动系统
// 实现流体在设备、管线中流动
2024-01-09 09:39:03 +08:00
// 流体驱动源(风机、泵、组合式空调)
2023-12-27 18:11:27 +08:00
type FluidDriverSystem struct {
2024-01-09 09:39:03 +08:00
queryFluidDriver *ecs.Query //流体驱动源
drivePathMap map[string][]*SearchedPath //key pipePortId,value 驱动源驱动流体的路径
queryFluidPipe *ecs.Query
2023-12-27 18:11:27 +08:00
}
func NewFluidDriverSystem() *FluidDriverSystem {
return &FluidDriverSystem{
2024-01-09 09:39:03 +08:00
queryFluidDriver: ecs.NewQuery(filter.Contains(component.UidType, component.FluidDriverType)),
queryFluidPipe: ecs.NewQuery(filter.Contains(component.UidType, component.PipeFluidType)),
2023-12-27 18:11:27 +08:00
}
}
2023-12-29 17:00:26 +08:00
// 获取流体流动路径
func (s *FluidDriverSystem) findFluidPath(fromDevice repository.Identity, fromDevicePortPipe repository.PipePort, fromIsStart bool) []*SearchedPath {
pipePortId := fromDevicePortPipe.PipePortId()
sp, ok := s.drivePathMap[pipePortId]
if !ok {
sp = newFluidDriverPathSearcher(fromDevice, fromDevicePortPipe, fromIsStart).search()
s.drivePathMap[pipePortId] = sp
}
return sp
2023-12-27 18:11:27 +08:00
}
func (s *FluidDriverSystem) Update(w ecs.World) {
2024-01-09 09:39:03 +08:00
s.queryFluidDriver.Each(w, func(entry *ecs.Entry) {
//fdId := component.UidType.Get(entry).Id
})
2023-12-29 17:00:26 +08:00
}
// 判断路径是否畅通
func (s *FluidDriverSystem) isFluidPathUnblocked(fp *SearchedPath, w ecs.World) bool {
for i := 0; i < len(fp.ViaPipes); i++ {
viaPipe := fp.ViaPipes[i]
viaDevice := viaPipe.Device().(*repository.Pipe).PortDevice(viaPipe.Port())
switch viaDevice.Device().Type() {
case proto.DeviceType_DeviceType_Environment: //默认畅通
case proto.DeviceType_DeviceType_PipeFitting: //默认畅通
case proto.DeviceType_DeviceType_AirPurificationDevice: //默认畅通
case proto.DeviceType_DeviceType_GasMixingChamber: //默认畅通
case proto.DeviceType_DeviceType_Valve:
if s.getValveOpenRate(w, viaDevice.Device().Id()) <= 0 { //阀门未开,路径阻塞
return false
}
case proto.DeviceType_DeviceType_CombinationAirConditioner:
if !s.isCombinationAirConditionerRunning(w, viaDevice.Device().Id()) { //组合式空调未开,路径阻塞
return false
}
}
}
return true
}
// 组合式空调是否在运行
func (s *FluidDriverSystem) isCombinationAirConditionerRunning(w ecs.World, id string) bool {
wd := entity.GetWorldData(w)
entry, ok := wd.EntityMap[id]
if ok {
air := component.AirConditioningType.Get(entry)
return air.Running
} else {
slog.Warn(fmt.Sprintf("World中未找到组合式空调[%s]的实体", id))
}
return false
}
// 获取阀门开度
func (s *FluidDriverSystem) getValveOpenRate(w ecs.World, valveId string) uint8 {
wd := entity.GetWorldData(w)
entry, ok := wd.EntityMap[valveId]
if ok {
return component.ValveType.Get(entry).OpenRate
} else {
slog.Warn(fmt.Sprintf("World中未找到阀门[%s]的实体", valveId))
}
return 0
}
//////////////////////////流体路径相关/////////////////////////////
type SearchedPath struct {
ViaPipes []repository.PipePort //路径所经过的有向管线
}
type fluidDriverPathSearcher struct {
fromDevice repository.Identity //起点设备
fromDevicePortPipe repository.PipePort //从起点设备的某个端口连接的管线的某个端口开始
fromIsStart bool //true-以设备输出口为起点false-以设备输入口为起点
searchedPaths []*fluidPath //搜索到的路径
excludePipeIds []string //排除经过这些管线的路径
}
func newFluidDriverPathSearcher(fromDevice repository.Identity, fromDevicePortPipe repository.PipePort, fromIsStart bool) *fluidDriverPathSearcher {
return &fluidDriverPathSearcher{fromDevice: fromDevice, fromDevicePortPipe: fromDevicePortPipe, fromIsStart: fromIsStart}
}
func (s *fluidDriverPathSearcher) search() []*SearchedPath {
var rt []*SearchedPath
if !s.exclude(s.fromDevicePortPipe.Device().Id()) {
2024-01-09 09:39:03 +08:00
searchContext := &fluidPath{viaPipeFittings: make(map[string]string)}
2023-12-29 17:00:26 +08:00
searchContext.addPipe(s.fromDevicePortPipe)
s.doSearch(searchContext)
} else {
return rt
}
//
for _, fp := range s.searchedPaths {
fpLen := len(fp.viaPipes)
path := &SearchedPath{}
if !s.fromIsStart { //以输入口为起点,须反转搜索结果
for i := fpLen - 1; i >= 0; i-- {
viaPipe := fp.viaPipes[i]
path.ViaPipes = append(path.ViaPipes, viaPipe.ToOtherPort())
}
} else {
for _, viaPipe := range fp.viaPipes {
path.ViaPipes = append(path.ViaPipes, viaPipe)
}
}
rt = append(rt, path)
}
//
return rt
}
func (s *fluidDriverPathSearcher) exclude(pipeId string) bool {
for _, excludePipeId := range s.excludePipeIds {
if excludePipeId == pipeId {
return true
}
}
return false
}
func (s *fluidDriverPathSearcher) addSearchedPath(searchContext *fluidPath) {
s.searchedPaths = append(s.searchedPaths, searchContext)
}
2024-01-09 09:39:03 +08:00
// 搜索
2023-12-29 17:00:26 +08:00
func (s *fluidDriverPathSearcher) doSearch(searchContext *fluidPath) {
2024-01-09 09:39:03 +08:00
nextViaPipes, end := searchContext.nextViaPathPipes()
2023-12-29 17:00:26 +08:00
lenNextPipes := len(nextViaPipes)
2024-01-09 09:39:03 +08:00
if end {
2023-12-29 17:00:26 +08:00
s.addSearchedPath(searchContext)
} else {
2024-01-09 09:39:03 +08:00
if lenNextPipes == 1 {
if !searchContext.viaPipe(nextViaPipes[0].Device().Id()) && !s.exclude(nextViaPipes[0].Device().Id()) {
searchContext.addPipe(nextViaPipes[0])
s.doSearch(searchContext)
2023-12-29 17:00:26 +08:00
}
2024-01-09 09:39:03 +08:00
} else {
for _, nextViaPipe := range nextViaPipes {
if searchContext.viaPipe(nextViaPipe.Device().Id()) { //舍弃回头路径
continue
}
if s.exclude(nextViaPipe.Device().Id()) { //舍弃排除路径
continue
}
//
cp := searchContext.clone()
cp.addPipe(nextViaPipe)
s.doSearch(cp)
2023-12-29 17:00:26 +08:00
}
2023-12-27 18:11:27 +08:00
}
}
}
2023-12-29 17:00:26 +08:00
2024-01-09 09:39:03 +08:00
// 从当前管线找下一个管线
// 泵、风机、空调 提供驱动力,承接进出
// 返回bool : true-搜索达终点
func (p *fluidPath) nextViaPathPipes() ([]repository.PipePort, bool) {
2023-12-29 17:00:26 +08:00
nextDevice := p.nextDevice()
2024-01-09 09:39:03 +08:00
//
2023-12-29 17:00:26 +08:00
switch nextDevice.Type() {
case proto.DeviceType_DeviceType_PipeFitting:
2024-01-09 09:39:03 +08:00
{
if _, has := p.viaPipeFittings[nextDevice.Id()]; has { //排除已经经过的管件的路径
return nil, false
} else {
p.viaPipeFittings[nextDevice.Id()] = nextDevice.Id()
return p.nextDeviceViaPipes(nextDevice.(*repository.PipeFitting).Ports(), p.curPipe), false
}
}
2023-12-29 17:00:26 +08:00
case proto.DeviceType_DeviceType_Valve:
2024-01-09 09:39:03 +08:00
return p.nextDeviceViaPipes(nextDevice.(*repository.Valve).Ports(), p.curPipe), false
case proto.DeviceType_DeviceType_GasMixingChamber: //静压箱
return p.nextGasMixingChamberViaPipes(nextDevice.(*repository.GasMixingChamber), p.curPipe), false
case proto.DeviceType_DeviceType_AirPurificationDevice: //净化装置
return p.nextDeviceViaPipes(nextDevice.(*repository.AirPurificationDevice).Ports(), p.curPipe), false
case proto.DeviceType_DeviceType_Environment: //环境
fallthrough
case proto.DeviceType_DeviceType_AirPavilion: //风亭
fallthrough
case proto.DeviceType_DeviceType_CombinationAirConditioner: //组合式空调
return nil, true //路径搜索终点
2023-12-29 17:00:26 +08:00
default:
slog.Warn("管线路径中的设备[%d]无法处理", nextDevice.Type())
}
2024-01-09 09:39:03 +08:00
return nil, false //排除(舍弃)该路径搜索
2023-12-29 17:00:26 +08:00
}
///////////////////////////////////////////////////////////////////////////////////////////
func (p *fluidPath) nextDeviceViaPipes(deviceAllPipePorts []*repository.PipePort, preViaPipe repository.PipePort) []repository.PipePort {
var rt []repository.PipePort
findPreViaPipe := false
for _, pfPort := range deviceAllPipePorts {
if preViaPipe.Device().Id() != pfPort.Device().Id() {
rt = append(rt, *pfPort)
} else {
findPreViaPipe = true
}
}
if !findPreViaPipe { //校验数据
panic("preViaPipe没有与设备连接")
}
return rt
}
// 组合式空调
func (p *fluidPath) nextCombinationAirConditionerViaPipes(nextDevice *repository.CombinationAirConditioner, preViaPipe repository.PipePort) []repository.PipePort {
var rt []repository.PipePort
if preViaPipe.Device().Id() == nextDevice.PortA.Device().Id() { //从组合式空调的A口进入
rt = append(rt, *nextDevice.PortB)
if nextDevice.PortC != nil {
rt = append(rt, *nextDevice.PortC)
}
return rt
} else if preViaPipe.Device().Id() == nextDevice.PortD.Device().Id() { //从组合式空调的D口进入
return rt
}
return rt
}
// 静压箱
func (p *fluidPath) nextGasMixingChamberViaPipes(nextDevice *repository.GasMixingChamber, preViaPipe repository.PipePort) []repository.PipePort {
var rt []repository.PipePort
if nextDevice.IsInput(preViaPipe.Device().Id()) {
for _, out := range nextDevice.PortsB {
rt = append(rt, *out)
}
}
return rt
}
type fluidPath struct {
2024-01-09 09:39:03 +08:00
curPipe repository.PipePort //路径中当前有向管线
viaPipes []repository.PipePort //路径所经过的有向管线
viaPipeFittings map[string]string //经过的管件用于排除闭环路径key和value均为deviceId
2023-12-29 17:00:26 +08:00
}
func (p *fluidPath) addPipe(viaPipe repository.PipePort) {
p.viaPipes = append(p.viaPipes, viaPipe)
p.curPipe = viaPipe
}
func (p *fluidPath) viaPipe(pipeId string) bool {
for _, vp := range p.viaPipes {
if vp.Device().Id() == pipeId {
return true
}
}
return false
}
func (p *fluidPath) clone() *fluidPath {
2024-01-09 09:39:03 +08:00
cp := &fluidPath{viaPipes: make([]repository.PipePort, 0, len(p.viaPipes)), curPipe: p.curPipe, viaPipeFittings: make(map[string]string)}
2023-12-29 17:00:26 +08:00
copy(cp.viaPipes, p.viaPipes)
2024-01-09 09:39:03 +08:00
for k, v := range p.viaPipeFittings {
cp.viaPipeFittings[k] = v
}
2023-12-29 17:00:26 +08:00
return cp
}
func (p *fluidPath) nextDevice() repository.Identity {
if p.curPipe.Port() == proto.Port_A {
return p.curPipe.Device().(*repository.Pipe).PortB.Device()
} else {
return p.curPipe.Device().(*repository.Pipe).PortA.Device()
}
}