modelRT/database/query_topologic.go

177 lines
5.6 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/constant"
"modelRT/diagram"
"modelRT/orm"
"modelRT/sql"
"github.com/gofrs/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// QueryTopologic return the topologic info of the circuit diagram
func QueryTopologic(ctx context.Context, tx *gorm.DB, logger *zap.Logger) ([]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, constant.UUIDNilStr).Scan(&topologics)
if result.Error != nil {
logger.Error("query circuit diagram topologic info by start node uuid failed", zap.String("start_node_uuid", constant.UUIDNilStr), zap.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, logger *zap.Logger, componentTypeMap map[uuid.UUID]int) error {
topologicInfos, err := QueryTopologic(ctx, tx, logger)
if err != nil {
logger.Error("query topologic info failed", zap.Error(err))
return err
}
// err = InitCircuitDiagramTopologic(topologicInfos, componentTypeMap)
// if err != nil {
// logger.Error("init topologic failed", zap.Error(err))
// return err
// }
_, err = BuildMultiBranchTree(topologicInfos, componentTypeMap)
if err != nil {
logger.Error("init topologic failed", zap.Error(err))
return err
}
return nil
}
// InitCircuitDiagramTopologic return circuit diagram topologic info from postgres
func InitCircuitDiagramTopologic(topologicNodes []orm.Topologic, componentTypeMap map[uuid.UUID]int) error {
var rootVertex *diagram.MultiBranchTreeNode
for _, node := range topologicNodes {
if node.UUIDFrom == constant.UUIDNil {
// rootVertex = node.UUIDTo
var componentType int
componentType, ok := componentTypeMap[node.UUIDFrom]
if !ok {
return fmt.Errorf("can not get component type by uuid: %s", node.UUIDFrom)
}
rootVertex = diagram.NewMultiBranchTree(node.UUIDFrom, componentType)
break
}
}
if rootVertex == nil {
return fmt.Errorf("root vertex is nil")
}
for _, node := range topologicNodes {
if node.UUIDFrom == constant.UUIDNil {
var componentType int
componentType, ok := componentTypeMap[node.UUIDTo]
if !ok {
return fmt.Errorf("can not get component type by uuid: %s", node.UUIDTo)
}
nodeVertex := diagram.NewMultiBranchTree(node.UUIDTo, componentType)
rootVertex.AddChild(nodeVertex)
}
}
node := rootVertex
for _, nodeVertex := range node.Children {
nextVertexs := make([]*diagram.MultiBranchTreeNode, 0)
nextVertexs = append(nextVertexs, nodeVertex)
}
return nil
}
// TODO 电流互感器不单独划分间隔
// TODO 以母线、浇筑母线、变压器为间隔原件
func IntervalBoundaryDetermine(uuid uuid.UUID) bool {
// TODO 从diagramsOverview中根据 uuid 获取 component 信息
var componentID int64
diagram.GetComponentMap(componentID)
// TODO 判断 component 的类型是否为间隔
// TODO 0x1111A1B2C3D4,高四位表示可以成为间隔的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, componentTypeMap map[uuid.UUID]int) (*diagram.MultiBranchTreeNode, error) {
nodeMap := make(map[uuid.UUID]*diagram.MultiBranchTreeNode, len(topologics))
for _, topo := range topologics {
// skip special uuid
if _, exists := nodeMap[topo.UUIDFrom]; !exists {
var componentType int
if topo.UUIDTo != constant.UUIDNil {
var ok bool
componentType, ok = componentTypeMap[topo.UUIDFrom]
if !ok {
return nil, fmt.Errorf("can not get component type by uuid: %s", topo.UUIDFrom)
}
nodeMap[topo.UUIDFrom] = &diagram.MultiBranchTreeNode{
ID: topo.UUIDFrom,
NodeComponentType: componentType,
}
}
}
if _, exists := nodeMap[topo.UUIDTo]; !exists {
var componentType int
if topo.UUIDTo != constant.UUIDNil {
var ok bool
componentType, ok = componentTypeMap[topo.UUIDTo]
if !ok {
return nil, fmt.Errorf("can not get component type by uuid: %s", topo.UUIDTo)
}
}
nodeMap[topo.UUIDTo] = &diagram.MultiBranchTreeNode{
ID: topo.UUIDTo,
NodeComponentType: componentType,
}
}
}
for _, topo := range topologics {
var parent *diagram.MultiBranchTreeNode
if topo.UUIDFrom == constant.UUIDNil {
var componentType int
parent = &diagram.MultiBranchTreeNode{
ID: constant.UUIDNil,
NodeComponentType: componentType,
}
nodeMap[constant.UUIDNil] = parent
} else {
parent = nodeMap[topo.UUIDFrom]
}
child := nodeMap[topo.UUIDTo]
child.Parent = parent
parent.Children = append(parent.Children, child)
}
// return root vertex
root, exists := nodeMap[constant.UUIDNil]
if !exists {
return nil, fmt.Errorf("root node not found")
}
return root, nil
}