modelRT/database/query_topologic.go

148 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package database define database operation functions
package database
import (
"context"
"fmt"
"time"
"modelRT/constants"
"modelRT/diagram"
"modelRT/logger"
"modelRT/orm"
"modelRT/sql"
"github.com/gofrs/uuid"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// QueryTopologic return the topologic info of the circuit diagram
func QueryTopologic(ctx context.Context, tx *gorm.DB) ([]orm.Topologic, error) {
var topologics []orm.Topologic
// ctx超时判断
cancelCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
result := tx.WithContext(cancelCtx).Clauses(clause.Locking{Strength: "UPDATE"}).Raw(sql.RecursiveSQL, constants.UUIDNilStr).Scan(&topologics)
if result.Error != nil {
logger.Error(ctx, "query circuit diagram topologic info by start node uuid failed", "start_node_uuid", constants.UUIDNilStr, "error", result.Error)
return nil, result.Error
}
return topologics, nil
}
// QueryTopologicFromDB return the result of query topologic info from DB
func QueryTopologicFromDB(ctx context.Context, tx *gorm.DB) (*diagram.MultiBranchTreeNode, error) {
topologicInfos, err := QueryTopologic(ctx, tx)
if err != nil {
logger.Error(ctx, "query topologic info failed", "error", err)
return nil, err
}
tree, err := BuildMultiBranchTree(topologicInfos)
if err != nil {
logger.Error(ctx, "init topologic failed", "error", err)
return nil, err
}
return tree, nil
}
// InitCircuitDiagramTopologic return circuit diagram topologic info from postgres
func InitCircuitDiagramTopologic(topologicNodes []orm.Topologic) error {
var rootVertex *diagram.MultiBranchTreeNode
for _, node := range topologicNodes {
if node.UUIDFrom == constants.UUIDNil {
rootVertex = diagram.NewMultiBranchTree(node.UUIDFrom)
break
}
}
if rootVertex == nil {
return fmt.Errorf("root vertex is nil")
}
for _, node := range topologicNodes {
if node.UUIDFrom == constants.UUIDNil {
nodeVertex := diagram.NewMultiBranchTree(node.UUIDTo)
rootVertex.AddChild(nodeVertex)
}
}
node := rootVertex
for _, nodeVertex := range node.Children {
nextVertexs := make([]*diagram.MultiBranchTreeNode, 0)
nextVertexs = append(nextVertexs, nodeVertex)
}
return nil
}
// TODO 电流互感器不单独划分间隔,以母线、浇筑母线、变压器为间隔原件
func IntervalBoundaryDetermine(uuid uuid.UUID) bool {
diagram.GetComponentMap(uuid.String())
// TODO 判断 component 的类型是否为间隔
// TODO 0xA1B2C3D4,高四位表示可以成为间隔的compoent类型的值为FFFF,普通 component 类型的值为 0000。低四位中前二位表示component的一级类型例如母线 PT、母联/母分、进线等,低四位中后二位表示一级类型中包含的具体类型,例如母线 PT中包含的电压互感器、隔离开关、接地开关、避雷器、带电显示器等。
num := uint32(0xA1B2C3D4) // 八位16进制数
high16 := uint16(num >> 16)
fmt.Printf("原始值: 0x%X\n", num) // 输出: 0xA1B2C3D4
fmt.Printf("高十六位: 0x%X\n", high16) // 输出: 0xA1B2
return true
}
// BuildMultiBranchTree return the multi branch tree by topologic info and component type map
func BuildMultiBranchTree(topologics []orm.Topologic) (*diagram.MultiBranchTreeNode, error) {
nodeMap := make(map[uuid.UUID]*diagram.MultiBranchTreeNode, len(topologics)*2)
for _, topo := range topologics {
if _, exists := nodeMap[topo.UUIDFrom]; !exists {
// skip special uuid
if topo.UUIDTo != constants.UUIDNil {
nodeMap[topo.UUIDFrom] = &diagram.MultiBranchTreeNode{
ID: topo.UUIDFrom,
Children: make([]*diagram.MultiBranchTreeNode, 0),
}
}
}
if _, exists := nodeMap[topo.UUIDTo]; !exists {
// skip special uuid
if topo.UUIDTo != constants.UUIDNil {
nodeMap[topo.UUIDTo] = &diagram.MultiBranchTreeNode{
ID: topo.UUIDTo,
Children: make([]*diagram.MultiBranchTreeNode, 0),
}
}
}
}
for _, topo := range topologics {
var parent *diagram.MultiBranchTreeNode
if topo.UUIDFrom == constants.UUIDNil {
parent = &diagram.MultiBranchTreeNode{
ID: constants.UUIDNil,
}
nodeMap[constants.UUIDNil] = parent
} else {
parent = nodeMap[topo.UUIDFrom]
}
var child *diagram.MultiBranchTreeNode
if topo.UUIDTo == constants.UUIDNil {
child = &diagram.MultiBranchTreeNode{
ID: topo.UUIDTo,
}
} else {
child = nodeMap[topo.UUIDTo]
}
child.Parent = parent
parent.Children = append(parent.Children, child)
}
// return root vertex
root, exists := nodeMap[constants.UUIDNil]
if !exists {
return nil, fmt.Errorf("root node not found")
}
return root, nil
}