公里标数据构造

区段、物理区段、道岔区段、逻辑区段等概念区分抽象,重构实现
This commit is contained in:
soul-walker 2024-07-08 19:47:30 +08:00
parent b3271b497a
commit 97445763fd
6 changed files with 191 additions and 40 deletions

View File

@ -11,8 +11,8 @@ import (
)
func main() {
// slog.SetLogLoggerLevel(slog.LevelDebug)
slog.SetLogLoggerLevel(slog.LevelInfo)
slog.SetLogLoggerLevel(slog.LevelDebug)
// slog.SetLogLoggerLevel(slog.LevelInfo)
repo1 := repository.NewRepository("test1")
rtssGraphicStorage := data_proto.GetXian6STYG()
dataMapping := repository.NewDataMapping("1", rtssGraphicStorage)
@ -38,8 +38,13 @@ func main() {
dataMapping.SectionDataMap[section.Common.Id] = section
uid := getSectionUid(section, belongStation, dataMapping.GetLineInfo())
dataMapping.AddIdMapping(repository.NewIdMapping(section.Common.Id, uid))
sectionModel := model.NewSection(uid)
repo1.SectionMap[uid] = &modelimpl.Section{SectionImpl: sectionModel}
if section.SectionType == data_proto.Section_Physical {
sectionModel := model.NewPhysicalSection(uid)
repo1.PhysicalSectionMap[uid] = &modelimpl.PhysicalSection{PhysicalSectionImpl: sectionModel}
} else {
tsModel := model.NewTurnoutSection(uid)
repo1.TurnoutSectionMap[uid] = tsModel
}
}
for _, turnout := range rtssGraphicStorage.Turnouts {
if turnout.CentralizedStations == nil || len(turnout.CentralizedStations) == 0 {
@ -61,7 +66,7 @@ func main() {
// 构建道岔关系
buildTurnoutRelationships(dataMapping, repo1)
// 检查区段、道岔通道连接关系
err := repo1.CheckPipeLink()
err := repo1.CheckSectionAndTurnoutPipeLink()
if err != nil {
slog.Error("区段道岔连接关系检查错误", "errMsg", err)
return
@ -70,10 +75,15 @@ func main() {
}
// 构建区段、道岔公里标
buildKilometerMark(dataMapping, repo1)
err = repo1.CheckSectionAndTurnoutPortKms()
if err != nil {
slog.Error("区段道岔公里标检查错误", "errMsg", err)
return
}
// 构建link/linknode
repo1.BuildLinks()
// 检查link/linknode
err = repo1.CheckPipeLink()
err = repo1.CheckLinkAndLinkNodePipeLink()
if err != nil {
slog.Error("link/linknode连接关系检查错误", "errMsg", err)
return
@ -84,23 +94,57 @@ func main() {
// 构建区段、道岔公里标
func buildKilometerMark(dataMapping *repository.DataMapping, repo1 *repository.Repository) {
for _, turnout := range dataMapping.TurnoutDataMap {
if len(turnout.KilometerSystem) == 0 {
repo1.BuildErrorInfos = append(repo1.BuildErrorInfos, fmt.Errorf("构建区段、道岔公里标数据错误:道岔[id=%d]未关联任何公里标", turnout.Common.Id))
} else {
tks := turnout.KilometerSystem[0]
km := model.NewKilometerMark(tks.CoordinateSystem, convertKmDirection(tks.Direction), tks.Kilometer)
turnoutModel := repo1.TurnoutMap[dataMapping.IdMappingMap[turnout.Common.Id].Uid]
turnoutModel.(*modelimpl.Turnout).Km = km
}
}
for _, checkpoint := range dataMapping.AxleCountings {
if checkpoint.AxleCountingRef == nil || len(checkpoint.AxleCountingRef) == 0 {
repo1.BuildErrorInfos = append(repo1.BuildErrorInfos, fmt.Errorf("构建区段、道岔公里标错误:检测点[id=%d]未关联任何区段、道岔", checkpoint.Common.Id))
repo1.BuildErrorInfos = append(repo1.BuildErrorInfos, fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]未关联任何区段、道岔", checkpoint.Common.Id))
}
for _, linkship := range checkpoint.AxleCountingRef {
slog.Info("区段检测点关联数据", "code", checkpoint.Code, "linkship", fmt.Sprintf("{type=%s, id=%d, port=%s}", linkship.DeviceType, linkship.Id, linkship.DevicePort))
slog.Debug("区段检测点关联数据", "code", checkpoint.Code, "linkship", fmt.Sprintf("{type=%s, id=%d, port=%s}", linkship.DeviceType, linkship.Id, linkship.DevicePort))
idmapping := dataMapping.IdMappingMap[linkship.Id]
if idmapping == nil {
repo1.BuildErrorInfos = append(repo1.BuildErrorInfos, fmt.Errorf("构建区段、道岔公里标错误:检测点[id=%d]关联的{type=%s,id=%d}不存在", checkpoint.Common.Id, linkship.DeviceType, linkship.Id))
repo1.BuildErrorInfos = append(repo1.BuildErrorInfos, fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]关联的{type=%s,id=%d}不存在", checkpoint.Common.Id, linkship.DeviceType, linkship.Id))
continue
}
if linkship.DeviceType == data_proto.RelatedRef_Section {
sectionModel := repo1.SectionMap[idmapping.Uid]
if sectionModel == nil {
panic(fmt.Errorf("构建区段、道岔公里标错误:检测点[id=%d]关联的区段模型[uid=%s]不存在", checkpoint.Common.Id, idmapping.Uid))
sectionModel, ok := repo1.PhysicalSectionMap[idmapping.Uid]
if !ok {
panic(fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]关联的区段模型[uid=%s]不存在", checkpoint.Common.Id, idmapping.Uid))
}
sectionModel.(*modelimpl.Section).PaKm = model.NewKilometerMark(checkpoint.KilometerSystem.CoordinateSystem, convertKmDirection(checkpoint.KilometerSystem.Direction), checkpoint.KilometerSystem.Kilometer)
km := model.NewKilometerMark(checkpoint.KilometerSystem.CoordinateSystem, convertKmDirection(checkpoint.KilometerSystem.Direction), checkpoint.KilometerSystem.Kilometer)
if linkship.DevicePort == data_proto.RelatedRef_A {
sectionModel.(*modelimpl.PhysicalSection).PaKm = km
} else if linkship.DevicePort == data_proto.RelatedRef_B {
sectionModel.(*modelimpl.PhysicalSection).PbKm = km
} else {
panic(fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]关联的区段模型[uid=%s]未知的端口类型: %v", checkpoint.Common.Id, idmapping.Uid, linkship.DevicePort))
}
} else if linkship.DeviceType == data_proto.RelatedRef_Turnout {
turnoutModel, ok := repo1.TurnoutMap[idmapping.Uid]
if !ok {
panic(fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]关联的道岔模型[uid=%s]不存在", checkpoint.Common.Id, idmapping.Uid))
}
km := model.NewKilometerMark(checkpoint.KilometerSystem.CoordinateSystem, convertKmDirection(checkpoint.KilometerSystem.Direction), checkpoint.KilometerSystem.Kilometer)
if linkship.DevicePort == data_proto.RelatedRef_A {
turnoutModel.(*modelimpl.Turnout).PaKm = km
} else if linkship.DevicePort == data_proto.RelatedRef_B {
turnoutModel.(*modelimpl.Turnout).PbKm = km
} else if linkship.DevicePort == data_proto.RelatedRef_C {
turnoutModel.(*modelimpl.Turnout).PcKm = km
} else {
panic(fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]关联的道岔模型[uid=%s]未知的端口类型: %v", checkpoint.Common.Id, idmapping.Uid, linkship.DevicePort))
}
} else {
panic(fmt.Errorf("构建区段、道岔公里标数据错误:检测点[id=%d]未知的关联设备类型: %v", checkpoint.Common.Id, linkship.DeviceType))
}
}
}
@ -135,7 +179,7 @@ func buildSectionRelationships(dataMapping *repository.DataMapping, repo1 *repos
if idmapping == nil {
panic(fmt.Errorf("构建区段关系错误idmapping异常为空"))
}
sectionModel := repo1.SectionMap[idmapping.Uid]
sectionModel := repo1.PhysicalSectionMap[idmapping.Uid]
buildSectionPortLinkRelation(section.PaRef, sectionModel, model.PipePortA, repo1, dataMapping)
buildSectionPortLinkRelation(section.PbRef, sectionModel, model.PipePortB, repo1, dataMapping)
}
@ -148,7 +192,7 @@ func buildTurnoutPortLinkship(pref *data_proto.RelatedRef, sourceModel model.Tur
if pref.DeviceType == data_proto.RelatedRef_Section {
idmapping2 := dataMapping.IdMappingMap[pref.Id]
if idmapping2 != nil {
sectionModel := repo1.SectionMap[idmapping2.Uid]
sectionModel := repo1.PhysicalSectionMap[idmapping2.Uid]
if sectionModel != nil {
sourceModel.SetLinkedElement(port, model.NewPipeLink(sectionModel, convertPort(pref.DevicePort)))
}
@ -165,14 +209,14 @@ func buildTurnoutPortLinkship(pref *data_proto.RelatedRef, sourceModel model.Tur
}
}
func buildSectionPortLinkRelation(pref *data_proto.RelatedRef, sourceModel model.Section, port model.PipePort, repo1 *repository.Repository, dataMapping *repository.DataMapping) {
func buildSectionPortLinkRelation(pref *data_proto.RelatedRef, sourceModel model.PhysicalSection, port model.PipePort, repo1 *repository.Repository, dataMapping *repository.DataMapping) {
if pref == nil {
return
}
if pref.DeviceType == data_proto.RelatedRef_Section {
idmapping2 := dataMapping.IdMappingMap[pref.Id]
if idmapping2 != nil {
sectionModel := repo1.SectionMap[idmapping2.Uid]
sectionModel := repo1.PhysicalSectionMap[idmapping2.Uid]
if sectionModel != nil {
sourceModel.SetLinkedElement(port, model.NewPipeLink(sectionModel, convertPort(pref.DevicePort)))
}

View File

@ -2,6 +2,6 @@ package modelimpl
import "joylink.club/rtss-core/model"
type Section struct {
*model.SectionImpl
type PhysicalSection struct {
*model.PhysicalSectionImpl
}

View File

@ -36,6 +36,10 @@ func (km *KilometerMark) Coordinate() string {
return km.coordinate
}
func (km *KilometerMark) Value() int64 {
return km.value
}
// 是否为同一坐标系
func (km *KilometerMark) IsCoordinateEqual(coordinate string) bool {
return km.coordinate == coordinate

View File

@ -138,21 +138,24 @@ func (t *TwoPortsPipeElementImpl) OppositePipeLink(port PipePort) *PipeLink {
func (s *TwoPortsPipeElementImpl) SetLinkedElement(port PipePort, pipeLink *PipeLink) error {
if port == PipePortA {
if s.paPipeLink != nil {
return fmt.Errorf("区段uid=%s端口A已经设置关联元素: {uid=%s, port=%s}", s.uid, s.paPipeLink.Pipe.Uid(), s.paPipeLink.Port)
return fmt.Errorf("区段{uid=%s}端口A已经设置关联元素: {uid=%s, port=%s}", s.uid, s.paPipeLink.Pipe.Uid(), s.paPipeLink.Port)
}
s.paPipeLink = pipeLink
} else if port == PipePortB {
if s.pbPipeLink != nil {
return fmt.Errorf("区段uid=%s端口B已经设置关联元素: {uid=%s, port=%s}", s.uid, s.pbPipeLink.Pipe.Uid(), s.pbPipeLink.Port)
return fmt.Errorf("区段{uid=%s}端口B已经设置关联元素: {uid=%s, port=%s}", s.uid, s.pbPipeLink.Pipe.Uid(), s.pbPipeLink.Port)
}
s.pbPipeLink = pipeLink
} else {
return fmt.Errorf("区段uid=%s设置关联元素端口错误,不支持C端口", s.uid)
return fmt.Errorf("区段{uid=%s}设置关联元素端口错误,不支持C端口", s.uid)
}
return nil
}
func (s *TwoPortsPipeElementImpl) CheckPipeLink() error {
if s.paPipeLink == nil && s.pbPipeLink == nil {
return fmt.Errorf("区段{uid=%s}两端都没有关联通道连接关系", s.uid)
}
err := checkPipePortLink(s, PipePortA, s.paPipeLink)
if err != nil {
return err
@ -201,17 +204,17 @@ func (t *ThreePortsPipeElementImpl) GetLinkedElement(port PipePort) *PipeLink {
func (t *ThreePortsPipeElementImpl) SetLinkedElement(port PipePort, pipeLink *PipeLink) error {
if port == PipePortA {
if t.paPipeLink != nil {
return fmt.Errorf("道岔uid=%s端口A已经设置关联元素: {uid=%s, port=%s}", t.uid, t.paPipeLink.Pipe.Uid(), t.paPipeLink.Port)
return fmt.Errorf("道岔{uid=%s}端口A已经设置关联元素: {uid=%s, port=%s}", t.uid, t.paPipeLink.Pipe.Uid(), t.paPipeLink.Port)
}
t.paPipeLink = pipeLink
} else if port == PipePortB {
if t.pbPipeLink != nil {
return fmt.Errorf("道岔uid=%s端口B已经设置关联元素: {uid=%s, port=%s}", t.uid, t.pbPipeLink.Pipe.Uid(), t.pbPipeLink.Port)
return fmt.Errorf("道岔{uid=%s}端口B已经设置关联元素: {uid=%s, port=%s}", t.uid, t.pbPipeLink.Pipe.Uid(), t.pbPipeLink.Port)
}
t.pbPipeLink = pipeLink
} else if port == PipePortC {
if t.pcPipeLink != nil {
return fmt.Errorf("道岔uid=%s端口C已经设置关联元素: {uid=%s, port=%s}", t.uid, t.pcPipeLink.Pipe.Uid(), t.pcPipeLink.Port)
return fmt.Errorf("道岔{uid=%s}端口C已经设置关联元素: {uid=%s, port=%s}", t.uid, t.pcPipeLink.Pipe.Uid(), t.pcPipeLink.Port)
}
t.pcPipeLink = pipeLink
}

View File

@ -2,32 +2,84 @@ package model
// 区段
type Section interface {
RtssModel
}
// 物理区段(非道岔区段)
type PhysicalSection interface {
TwoPortsPipeElement
// 获取A端和B端的公里标
GetPaKm() *KilometerMark
GetPbKm() *KilometerMark
}
type SectionImpl struct {
// 道岔区段
type TurnoutSection interface {
Section
// 获取关联的道岔列表
GetTurnouts() []Turnout
}
// 逻辑区段
type LogicalSection interface {
Section
// 获取A端和B端的公里标
GetPaKm() *KilometerMark
GetPbKm() *KilometerMark
}
type PhysicalSectionImpl struct {
*TwoPortsPipeElementImpl
PaKm *KilometerMark
PbKm *KilometerMark
}
var _ Section = (*SectionImpl)(nil)
var _ PhysicalSection = (*PhysicalSectionImpl)(nil)
func NewSection(uid string) *SectionImpl {
return &SectionImpl{
func NewPhysicalSection(uid string) *PhysicalSectionImpl {
return &PhysicalSectionImpl{
TwoPortsPipeElementImpl: &TwoPortsPipeElementImpl{
uid: uid,
},
}
}
func (s *SectionImpl) GetPaKm() *KilometerMark {
func (s *PhysicalSectionImpl) GetPaKm() *KilometerMark {
return s.PaKm
}
func (s *SectionImpl) GetPbKm() *KilometerMark {
func (s *PhysicalSectionImpl) GetPbKm() *KilometerMark {
return s.PbKm
}
type SectionImpl struct {
uid string
}
func (s *SectionImpl) Uid() string {
return s.uid
}
var _ TurnoutSection = (*TurnoutSectionImpl)(nil)
type TurnoutSectionImpl struct {
*SectionImpl
Turnouts []Turnout
}
func NewTurnoutSection(uid string) *TurnoutSectionImpl {
return &TurnoutSectionImpl{
SectionImpl: &SectionImpl{
uid: uid,
},
Turnouts: make([]Turnout, 0),
}
}
func (t *TurnoutSectionImpl) AddTurnout(turnout Turnout) {
t.Turnouts = append(t.Turnouts, turnout)
}
func (t *TurnoutSectionImpl) GetTurnouts() []Turnout {
return t.Turnouts
}

View File

@ -15,8 +15,12 @@ type Repo interface {
GetStationByUid(uid string) model.Station
GetSectionByUid(uid string) model.Section
GetTurnoutByUid(uid string) model.Turnout
// 检查通道连接关系
CheckPipeLink() error
// 检查区段、道岔通道连接关系
CheckSectionAndTurnoutPipeLink() error
// 检查区段、道岔公里标
CheckSectionAndTurnoutPortKms() error
// 检查Link、LinkNode通道连接关系
CheckLinkAndLinkNodePipeLink() error
// 转换公里标
ConvertKilometerMark(km *model.KilometerMark, targetCoordinate string) (int64, error)
}
@ -27,7 +31,8 @@ type RepoImpl struct {
id string
BuildErrorInfos []error
StationMap map[string]model.Station
SectionMap map[string]model.Section
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
@ -38,7 +43,8 @@ func NewRepo(id string) *RepoImpl {
return &RepoImpl{
id: id,
StationMap: make(map[string]model.Station),
SectionMap: make(map[string]model.Section),
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),
@ -47,6 +53,9 @@ func NewRepo(id string) *RepoImpl {
}
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
@ -59,9 +68,40 @@ func (r *RepoImpl) ConvertKilometerMark(km *model.KilometerMark, targetCoordinat
return 0, fmt.Errorf("未找到公里标转换配置: %s<->%s, 全部配置项为: %s", km.Coordinate(), targetCoordinate, strings.Join(existConfigs, ","))
}
// CheckPipeLink implements Repo.
func (r *RepoImpl) CheckPipeLink() error {
for _, section := range r.SectionMap {
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)
@ -73,6 +113,14 @@ func (r *RepoImpl) CheckPipeLink() error {
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()
@ -94,7 +142,7 @@ func (r *RepoImpl) CheckPipeLink() error {
// GetSectionByUid implements Repo.
func (r *RepoImpl) GetSectionByUid(uid string) model.Section {
return r.SectionMap[uid]
return r.PhysicalSectionMap[uid]
}
// GetStationByUid implements Repo.
@ -157,7 +205,7 @@ func walkFromTurnoutPortToNextAndBuildLink(turnout model.Turnout, port model.Pip
repo1.LinkMap[link.Uid()] = link
return nextTurnout
} else {
ple = ple.Pipe.(model.Section).OppositePipeLink(ple.Port)
ple = ple.Pipe.(model.PhysicalSection).OppositePipeLink(ple.Port)
}
}
}