rtss-core/repo/repo.go

270 lines
8.3 KiB
Go
Raw Normal View History

2024-06-07 18:38:38 +08:00
package repo
import (
"errors"
"fmt"
"log/slog"
"strings"
"joylink.club/rtss-core/model"
)
2024-06-19 19:29:46 +08:00
2024-06-07 18:38:38 +08:00
type Repo interface {
// 模型仓库id
Id() string
2024-06-19 19:29:46 +08:00
GetStationByUid(uid string) model.Station
GetSectionByUid(uid string) model.Section
GetTurnoutByUid(uid string) model.Turnout
// 检查区段、道岔通道连接关系
CheckSectionAndTurnoutPipeLink() error
// 检查区段、道岔公里标
CheckSectionAndTurnoutPortKms() error
// 检查Link、LinkNode通道连接关系
CheckLinkAndLinkNodePipeLink() error
// 转换公里标
ConvertKilometerMark(km *model.KilometerMark, targetCoordinate string) (int64, error)
2024-06-07 18:38:38 +08:00
}
var _ Repo = (*RepoImpl)(nil)
type RepoImpl struct {
id string
BuildErrorInfos []error
StationMap map[string]model.Station
PhysicalSectionMap map[string]model.PhysicalSection
TurnoutSectionMap map[string]model.TurnoutSection
TurnoutMap map[string]model.Turnout
LinkNodeMap map[string]model.LinkNode
LinkMap map[string]model.Link
KilometerMarkConverters []model.KilometerMarkConverter
}
func NewRepo(id string) *RepoImpl {
return &RepoImpl{
id: id,
StationMap: make(map[string]model.Station),
PhysicalSectionMap: make(map[string]model.PhysicalSection),
TurnoutSectionMap: make(map[string]model.TurnoutSection),
TurnoutMap: make(map[string]model.Turnout),
LinkNodeMap: make(map[string]model.LinkNode),
LinkMap: make(map[string]model.Link),
KilometerMarkConverters: make([]model.KilometerMarkConverter, 0),
}
}
func (r *RepoImpl) ConvertKilometerMark(km *model.KilometerMark, targetCoordinate string) (int64, error) {
if km.Coordinate() == targetCoordinate {
return km.Value(), nil
}
for _, converter := range r.KilometerMarkConverters {
if converter.IsMatch(km, targetCoordinate) {
return converter.Convert(km, targetCoordinate), nil
}
}
existConfigs := make([]string, 0)
for _, converter := range r.KilometerMarkConverters {
existConfigs = append(existConfigs, converter.Debug())
}
return 0, fmt.Errorf("未找到公里标转换配置: %s<->%s, 全部配置项为: %s", km.Coordinate(), targetCoordinate, strings.Join(existConfigs, ","))
}
func (r *RepoImpl) CheckSectionAndTurnoutPortKms() error {
for _, section := range r.PhysicalSectionMap {
slog.Debug("检查区段公里标", "uid", section.Uid(), "A端公里标", section.GetPaKm(), "B端公里标", section.GetPbKm())
if section.GetPaKm() == nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, fmt.Errorf("区段[uid=%s]无A端公里标", section.Uid()))
}
if section.GetPbKm() == nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, fmt.Errorf("区段[uid=%s]无B端公里标", section.Uid()))
}
}
for _, turnout := range r.TurnoutMap {
slog.Debug("检查道岔公里标", "uid", turnout.Uid(), "公里标", turnout.GetKm(), "A端公里标", turnout.GetPaKm(), "B端公里标", turnout.GetPbKm(), "C端公里标", turnout.GetPcKm())
if turnout.GetKm() == nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, fmt.Errorf("道岔[uid=%s]无公里标", turnout.Uid()))
}
if turnout.GetPaKm() == nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, fmt.Errorf("道岔[uid=%s]无A端公里标", turnout.Uid()))
}
if turnout.GetPbKm() == nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, fmt.Errorf("道岔[uid=%s]无B端公里标", turnout.Uid()))
}
if turnout.GetPcKm() == nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, fmt.Errorf("道岔[uid=%s]无C端公里标", turnout.Uid()))
}
}
if len(r.BuildErrorInfos) > 0 {
return errors.Join(r.BuildErrorInfos...)
}
return nil
}
// CheckSectionAndTurnoutPipeLink implements Repo.
func (r *RepoImpl) CheckSectionAndTurnoutPipeLink() error {
for _, section := range r.PhysicalSectionMap {
err := section.CheckPipeLink()
if err != nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, err)
}
}
for _, turnout := range r.TurnoutMap {
err := turnout.CheckPipeLink()
if err != nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, err)
}
}
if len(r.BuildErrorInfos) > 0 {
return errors.Join(r.BuildErrorInfos...)
}
return nil
}
// CheckLinkAndLinkNodePipeLink implements Repo.
func (r *RepoImpl) CheckLinkAndLinkNodePipeLink() error {
slog.Debug("检查通道连接关系", "link数量", len(r.LinkMap))
for _, link := range r.LinkMap {
err := link.CheckPipeLink()
if err != nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, err)
}
}
for _, linkNode := range r.LinkNodeMap {
err := linkNode.CheckPipeLink()
if err != nil {
r.BuildErrorInfos = append(r.BuildErrorInfos, err)
}
}
if len(r.BuildErrorInfos) > 0 {
return errors.Join(r.BuildErrorInfos...)
}
return nil
}
// GetSectionByUid implements Repo.
func (r *RepoImpl) GetSectionByUid(uid string) model.Section {
return r.PhysicalSectionMap[uid]
}
// GetStationByUid implements Repo.
func (r *RepoImpl) GetStationByUid(uid string) model.Station {
return r.StationMap[uid]
}
// GetTurnoutByUid implements Repo.
func (r *RepoImpl) GetTurnoutByUid(uid string) model.Turnout {
return r.TurnoutMap[uid]
}
// Id implements Repo.
func (r *RepoImpl) Id() string {
return r.id
}
func (r *RepoImpl) BuildLinks() {
for _, turnout := range r.TurnoutMap {
walkOverTurnouts(turnout, r)
break // 从一个道岔遍历所有区段、道岔
}
}
func walkOverTurnouts(turnout model.Turnout, repo1 *RepoImpl) {
paNext := walkFromTurnoutPortToNextAndBuildLink(turnout, model.PipePortA, repo1)
if paNext != nil {
walkOverTurnouts(paNext, repo1)
}
pbNext := walkFromTurnoutPortToNextAndBuildLink(turnout, model.PipePortB, repo1)
if pbNext != nil {
walkOverTurnouts(pbNext, repo1)
}
pcNext := walkFromTurnoutPortToNextAndBuildLink(turnout, model.PipePortC, repo1)
if pcNext != nil {
walkOverTurnouts(pcNext, repo1)
}
}
func walkFromTurnoutPortToNextAndBuildLink(turnout model.Turnout, port model.PipePort, repo1 *RepoImpl) model.Turnout {
slog.Debug("walkFromTurnoutPortToNextAndBuildLink", "道岔id", turnout.Uid(), "端口", port)
ple := turnout.GetLinkedElement(port)
for {
if ple == nil {
link, exist := NewLinkNodeAndLinkAndBuildLinkship(turnout, port, nil, model.PipePortA, repo1)
if !exist {
repo1.LinkMap[link.Uid()] = link
}
slog.Debug("构建Link已存在", "LinkUid", link.Uid())
return nil
}
if ple.Pipe.IsThreePorts() {
nextTurnout := ple.Pipe.(model.Turnout)
nextPort := ple.Port
link, exist := NewLinkNodeAndLinkAndBuildLinkship(turnout, port, nextTurnout, nextPort, repo1)
if exist {
slog.Debug("构建Link已存在", "LinkUid", link.Uid())
return nil
}
repo1.LinkMap[link.Uid()] = link
return nextTurnout
} else {
ple = ple.Pipe.(model.PhysicalSection).OppositePipeLink(ple.Port)
}
}
}
func (r *RepoImpl) getOrBuildLinkNode(turnout model.Turnout) model.LinkNode {
node := r.LinkNodeMap[turnout.Uid()]
if node == nil {
node = model.NewLinkNode(turnout)
r.LinkNodeMap[turnout.Uid()] = node
}
return node
}
func (r *RepoImpl) isLinkExist(pla *model.PipeLink, plb *model.PipeLink) (bool, model.Link) {
for _, link := range r.LinkMap {
if link.IsEquals(pla, plb) {
return true, link
}
}
return false, nil
}
func NewLinkNodeAndLinkAndBuildLinkship(ta model.Turnout, tap model.PipePort, tb model.Turnout, tbp model.PipePort, repo1 *RepoImpl) (link model.Link, exist bool) {
if ta == nil && tb == nil {
panic("构造LinkNode错误: 道岔不能都为空")
}
var nodea model.LinkNode
var nodeb model.LinkNode
var pla *model.PipeLink
var plb *model.PipeLink
if ta == nil {
nodea = nil
nodeb = repo1.getOrBuildLinkNode(tb)
pla = nil
plb = model.NewPipeLink(nodeb, tbp)
} else if tb == nil {
nodea = repo1.getOrBuildLinkNode(ta)
nodeb = nil
pla = model.NewPipeLink(nodea, tap)
plb = nil
} else {
nodea = repo1.getOrBuildLinkNode(ta)
nodeb = repo1.getOrBuildLinkNode(tb)
pla = model.NewPipeLink(nodea, tap)
plb = model.NewPipeLink(nodeb, tbp)
2024-07-02 18:34:39 +08:00
}
exist, link = repo1.isLinkExist(pla, plb)
if exist {
return
}
link = model.NewLink(pla, plb)
link.SetLinkedElement(model.PipePortA, pla)
link.SetLinkedElement(model.PipePortB, plb)
if nodea != nil {
nodea.SetLinkedElement(tap, model.NewPipeLink(link, model.PipePortA))
2024-07-02 18:34:39 +08:00
}
if nodeb != nil {
nodeb.SetLinkedElement(tbp, model.NewPipeLink(link, model.PipePortB))
}
return
}