diff --git a/jl-ecs-go b/jl-ecs-go index c3b9d96..747a81e 160000 --- a/jl-ecs-go +++ b/jl-ecs-go @@ -1 +1 @@ -Subproject commit c3b9d965c607a2f29e0bdc586aba6851d4f29f13 +Subproject commit 747a81e44a4318a0390422156de44b7c3afddb06 diff --git a/repository/device_port.go b/repository/device_port.go index beb944e..34d1c04 100644 --- a/repository/device_port.go +++ b/repository/device_port.go @@ -7,8 +7,6 @@ type PortedDevice interface { // PortNum 端口数量 PortNum() int - // 关联设备端口 - bindDevicePort(port proto.Port, devicePort DevicePort) error //// 下一个设备端口 //Next(port proto.Port) DevicePort //// 其他设备端口 diff --git a/repository/link.go b/repository/link.go index c44863b..d8ef61f 100644 --- a/repository/link.go +++ b/repository/link.go @@ -1,8 +1,6 @@ package repository import ( - "errors" - "fmt" "joylink.club/rtsssimulation/repository/model/proto" ) @@ -13,11 +11,13 @@ type Link struct { aRelation *TurnoutPort bRelation *TurnoutPort + //组成Link的物理区段(按在link上偏移量从小到大排列) + physicalSections []*PhysicalSection aKm *proto.Kilometer bKm *proto.Kilometer - //Link上的模型((非区段边界)检测点、应答器、信号机、区段(为了位置换算方便)) + //Link上的模型((非区段边界)检测点、应答器、信号机) devices []Identity ////Link关联的模型,包含LinkNode @@ -52,21 +52,22 @@ func (l *Link) PortNum() int { return 2 } -func (l *Link) bindDevicePort(port proto.Port, devicePort DevicePort) error { - turnoutPort, isTurnoutPort := devicePort.(*TurnoutPort) - if !isTurnoutPort { - return errors.New(fmt.Sprintf("Link不能与[%s]类型的设备关联", devicePort.Device().Type())) - } +func (l *Link) PhysicalSections() []*PhysicalSection { + return l.physicalSections +} + +func (l *Link) bindTurnoutPort(port proto.Port, turnoutPort *TurnoutPort) { switch port { case proto.Port_A: l.aRelation = turnoutPort case proto.Port_B: l.bRelation = turnoutPort - default: - return errors.New(fmt.Sprintf("Link没有端口[%s]", port)) } l.bindKm(turnoutPort.turnout.km, port) - return nil +} + +func (l *Link) bindPhysicalSections(section *PhysicalSection) { + l.physicalSections = append(l.physicalSections, section) } func (l *Link) bindKm(km *proto.Kilometer, port proto.Port) { diff --git a/repository/physical_section.go b/repository/physical_section.go index caa2a74..7224c5d 100644 --- a/repository/physical_section.go +++ b/repository/physical_section.go @@ -26,7 +26,7 @@ type PhysicalSection struct { // 关联的设备(目前有信号机、应答器、(非区段边界)检测点) devices []Identity - //在Link上的区间(根据aKm和bKm计算出的) + //在Link上的区间(根据aKm和bKm计算出的,start的offset一定小于end的offset) startLinkPosition *LinkPosition endLinkPosition *LinkPosition } diff --git a/repository/repository_manager.go b/repository/repository_manager.go index bc02b7e..9b7a4a9 100644 --- a/repository/repository_manager.go +++ b/repository/repository_manager.go @@ -349,8 +349,6 @@ func buildLinksAndRelate(repo *Repository) error { if err != nil { return err } - //PhysicalSection关联Link - err = physicalSectionRelateLink(repo) return nil } @@ -374,10 +372,7 @@ func buildLinks(repo *Repository) error { }} linkIdGenerator++ //以此道岔端口作为Link的A端节点 - err := interrelateLinkAndTurnout(startTp, &LinkPort{link, proto.Port_A}) - if err != nil { - return err - } + interrelateLinkAndTurnout(repo, baseKm, startTp, &LinkPort{link, proto.Port_A}) //沿着道岔端口方向,一直寻找到轨道尽头或者下一个道岔端口。构建并关联中间的设备在link上的位置 endTp, endKm, err := findEndTurnoutPortOrEndKm(repo, link, startTp, baseKm) if err != nil { @@ -387,10 +382,7 @@ func buildLinks(repo *Repository) error { if endTp != nil { visitedTurnoutPortMap[buildTurnoutPortKey(endTp)] = true endKm = endTp.turnout.km - err = interrelateLinkAndTurnout(endTp, &LinkPort{link, proto.Port_B}) - if err != nil { - return err - } + interrelateLinkAndTurnout(repo, baseKm, endTp, &LinkPort{link, proto.Port_B}) } else { link.bindKm(endKm, proto.Port_B) } @@ -415,10 +407,10 @@ func findEndTurnoutPortOrEndKm(repo *Repository, link *Link, startTp *TurnoutPor visitedModelMap := make(map[string]bool) var currentDp DevicePort = startTp - devices := startTp.turnout.getDevicesByPort(startTp.port) + devices := startTp.turnout.findDevicesByPort(startTp.port) for { //遍历设备并构建、关联其在Link上的位置 - err = buildAndRelateDeviceLinkPositions(repo, link, baseKm, visitedModelMap, devices...) + err = relateDevicesAndLink(repo, link, baseKm, visitedModelMap, devices...) if err != nil { return nil, nil, err } @@ -427,13 +419,14 @@ func findEndTurnoutPortOrEndKm(repo *Repository, link *Link, startTp *TurnoutPor switch currentDp.Device().Type() { case proto.DeviceType_DeviceType_PhysicalSection: section := currentDp.Device().(*PhysicalSection) + relatePhysicalSectionAndLink(repo, section, link, baseKm) nextDp = section.findOtherDevicePort(currentDp.Port()) if nextDp == nil { endKm = section.findOtherBoundaryKmByPort(currentDp.Port()) } case proto.DeviceType_DeviceType_Turnout: turnout := currentDp.Device().(*Turnout) - nextDp = turnout.getDevicePortByPort(currentDp.Port()) + nextDp = turnout.findDevicePortByPort(currentDp.Port()) if nextDp == nil { endKm = turnout.findBoundaryKmByPort(currentDp.Port()) } @@ -450,8 +443,8 @@ func findEndTurnoutPortOrEndKm(repo *Repository, link *Link, startTp *TurnoutPor case proto.DeviceType_DeviceType_Turnout: nextIsTp = true endTp = nextDp.(*TurnoutPort) - devices = nextDp.Device().(*Turnout).getDevicesByPort(nextDp.Port()) - err = buildAndRelateDeviceLinkPositions(repo, link, baseKm, visitedModelMap, devices...) + devices = nextDp.Device().(*Turnout).findDevicesByPort(nextDp.Port()) + err = relateDevicesAndLink(repo, link, baseKm, visitedModelMap, devices...) if err != nil { return nil, nil, err } @@ -464,6 +457,22 @@ func findEndTurnoutPortOrEndKm(repo *Repository, link *Link, startTp *TurnoutPor return endTp, endKm, err } +func relatePhysicalSectionAndLink(repo *Repository, section *PhysicalSection, link *Link, baseKm *proto.Kilometer) { + link.bindPhysicalSections(section) + aKm, _ := convertKilometer(repo, section.aKm, baseKm.CoordinateSystem, baseKm.Direction) + bKm, _ := convertKilometer(repo, section.bKm, baseKm.CoordinateSystem, baseKm.Direction) + aOffset := number.Abs(aKm.Value - baseKm.Value) + bOffset := number.Abs(bKm.Value - baseKm.Value) + section.bindStartLinkPosition(&LinkPosition{ + link: link, + offset: number.Min(aOffset, bOffset), + }) + section.bindEndLinkPosition(&LinkPosition{ + link: link, + offset: number.Max(aOffset, bOffset), + }) +} + func getATurnoutPort(turnouts []*Turnout, visitedTurnoutMap map[string]bool) *TurnoutPort { portSlice := []proto.Port{proto.Port_A, proto.Port_B, proto.Port_C} for _, turnout := range turnouts { @@ -486,7 +495,7 @@ func buildTurnoutPortKey(tp *TurnoutPort) string { return fmt.Sprintf("%v-%s", tp.turnout, tp.port) } -func buildAndRelateDeviceLinkPositions(repo *Repository, link *Link, startKm *proto.Kilometer, visitedModelMap map[string]bool, devices ...Identity) error { +func relateDevicesAndLink(repo *Repository, link *Link, startKm *proto.Kilometer, visitedModelMap map[string]bool, devices ...Identity) error { for _, device := range devices { if visitedModelMap[device.Id()] { continue @@ -495,7 +504,6 @@ func buildAndRelateDeviceLinkPositions(repo *Repository, link *Link, startKm *pr if km == nil { continue } - link.bindDevices(device) convertedKm, err := convertKilometer(repo, km, startKm.CoordinateSystem, startKm.Direction) if err != nil { return err @@ -517,9 +525,16 @@ func buildAndRelateDeviceLinkPositions(repo *Repository, link *Link, startKm *pr return nil } -func interrelateLinkAndTurnout(tp *TurnoutPort, linkPort *LinkPort) error { +func interrelateLinkAndTurnout(repo *Repository, baseKm *proto.Kilometer, tp *TurnoutPort, linkPort *LinkPort) { tp.turnout.bindLinkPort(tp.port, linkPort) - return linkPort.link.bindDevicePort(linkPort.port, tp) + linkPort.link.bindTurnoutPort(linkPort.port, tp) + tpKm := tp.turnout.findBoundaryKmByPort(tp.port) + tpKm, _ = convertKilometer(repo, tpKm, baseKm.CoordinateSystem, baseKm.Direction) + offset := number.Abs(tpKm.Value - baseKm.Value) + tp.turnout.bindLinkPosition(tp.port, &LinkPosition{ + link: linkPort.link, + offset: offset, + }) } func findModelKm(model Identity) *proto.Kilometer { @@ -646,16 +661,3 @@ func sectionalCurvatureRelateLink(repo *Repository) error { } return nil } - -func physicalSectionRelateLink(repo *Repository) error { - for _, section := range repo.physicalSectionMap { - start, end, err := calculateLinkSegment(repo, section.aKm, section.bKm) - if err != nil { - return err - } - section.bindStartLinkPosition(start) - section.bindEndLinkPosition(end) - section.startLinkPosition.link.bindDevices(section) - } - return nil -} diff --git a/repository/turnout.go b/repository/turnout.go index 6852a36..95e6e71 100644 --- a/repository/turnout.go +++ b/repository/turnout.go @@ -25,11 +25,16 @@ type Turnout struct { bLinkPort *LinkPort cLinkPort *LinkPort - // A/B/C端口的区段边界的公里标 + // A/B/C端口的边界的公里标 aKm *proto.Kilometer bKm *proto.Kilometer cKm *proto.Kilometer + // A/B/C端口的边界在Link上的位置 + aLinkPosition *LinkPosition + bLinkPosition *LinkPosition + cLinkPosition *LinkPosition + // A/B/C方向关联的设备(目前有信号机、应答器、(非区段边界)检测点) aDevices []Identity bDevices []Identity @@ -75,9 +80,9 @@ func (t *Turnout) bindLinkPort(port proto.Port, linkPort *LinkPort) { case proto.Port_A: t.aLinkPort = linkPort case proto.Port_B: - t.aLinkPort = linkPort + t.bLinkPort = linkPort case proto.Port_C: - t.aLinkPort = linkPort + t.cLinkPort = linkPort } } @@ -95,6 +100,17 @@ func (t *Turnout) bindBoundaryKm(km *proto.Kilometer, port proto.Port) error { return nil } +func (t *Turnout) bindLinkPosition(port proto.Port, position *LinkPosition) { + switch port { + case proto.Port_A: + t.aLinkPosition = position + case proto.Port_B: + t.bLinkPosition = position + case proto.Port_C: + t.cLinkPosition = position + } +} + func (t *Turnout) bindDevice(device Identity, port proto.Port) { switch port { case proto.Port_A: @@ -130,7 +146,7 @@ func (t *Turnout) checkPoints() []*CheckPoint { } // 获取指定端口连接的设备端口 -func (t *Turnout) getDevicePortByPort(port proto.Port) DevicePort { +func (t *Turnout) findDevicePortByPort(port proto.Port) DevicePort { switch port { case proto.Port_A: return t.aDevicePort @@ -155,7 +171,7 @@ func (t *Turnout) findBoundaryKmByPort(port proto.Port) *proto.Kilometer { return nil } -func (t *Turnout) getDevicesByPort(port proto.Port) []Identity { +func (t *Turnout) findDevicesByPort(port proto.Port) []Identity { switch port { case proto.Port_A: return t.aDevices @@ -167,6 +183,18 @@ func (t *Turnout) getDevicesByPort(port proto.Port) []Identity { return nil } +func (t *Turnout) FindLinkPositionByPort(port proto.Port) *LinkPosition { + switch port { + case proto.Port_A: + return t.aLinkPosition + case proto.Port_B: + return t.bLinkPosition + case proto.Port_C: + return t.cLinkPosition + } + return nil +} + type TurnoutPort struct { turnout *Turnout port proto.Port @@ -179,3 +207,7 @@ func (t *TurnoutPort) Port() proto.Port { func (t *TurnoutPort) Device() PortedDevice { return t.turnout } + +func (t *TurnoutPort) Turnout() *Turnout { + return t.turnout +} diff --git a/util/number/number.go b/util/number/number.go index e289d68..e4f9e10 100644 --- a/util/number/number.go +++ b/util/number/number.go @@ -1,5 +1,7 @@ package number +import "math" + type Number interface { ~int | ~int8 | ~int16 | ~int32 | int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | @@ -27,3 +29,8 @@ func Max[T Number](a T, b T) T { } return b } + +func Abs[T Number](num T) T { + abs := math.Abs(float64(num)) + return T(abs) +}