怎么把cad从右边的图案特征学习到会标注按左边这样 wl图核

csharp 复制代码
好的,我来为CAD特征学习创建独立的WL模块,与现有的SolidWorks WL系统共享数据库但代码分离。

让我先看一下当前的目录结构,然后创建新的CAD专用模块:


好的,我来为CAD特征学习创建独立的WL模块,与SolidWorks的WL系统共享数据库但代码完全分离。


好的,我来创建独立的CAD WL学习模块,放在 `share/cad/wl_learning` 目录下,与SolidWorks的train模块完全分离,但共享同一个数据库。

## 1. 创建CAD WL图核实现

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace cad_tools
{
    /// <summary>
    /// CAD 2D图形节点 - 表示CAD图纸中的图形元素
    /// </summary>
    public class CADGraphEdgeNode
    {
        /// <summary>
        /// 节点ID
        /// </summary>
        public int Id { get; set; }
        
        /// <summary>
        /// 节点类型:Line, Arc, Circle, Polyline, Ellipse
        /// </summary>
        public string EdgeType { get; set; } = "Unknown";
        
        /// <summary>
        /// 当前WL标签
        /// </summary>
        public string CurrentLabel { get; set; } = "Unknown";
        
        /// <summary>
        /// 几何特征(长度、半径等)
        /// </summary>
        public double GeometryValue { get; set; }
        
        /// <summary>
        /// 角度特征
        /// </summary>
        public double Angle { get; set; }
        
        /// <summary>
        /// 是否水平
        /// </summary>
        public bool IsHorizontal { get; set; }
        
        /// <summary>
        /// 是否垂直
        /// </summary>
        public bool IsVertical { get; set; }
        
        /// <summary>
        /// 连接的节点ID列表
        /// </summary>
        public List<int> ConnectedNodes { get; set; } = new List<int>();
    }

    /// <summary>
    /// CAD 2D图 - 表示一个视图或图形的拓扑结构
    /// </summary>
    public class CADGraphEdgeGraph
    {
        /// <summary>
        /// 图形名称(视图名称或文件名)
        /// </summary>
        public string GraphName { get; set; } = "";
        
        /// <summary>
        /// 源文件名
        /// </summary>
        public string SourceFile { get; set; } = "";
        
        /// <summary>
        /// 节点列表
        /// </summary>
        public List<CADGraphEdgeNode> Nodes { get; set; } = new List<CADGraphEdgeNode>();
    }

    /// <summary>
    /// CAD WL图核实现 - 计算2D图形拓扑相似度
    /// </summary>
    public static class CADWLGraphKernel
    {
        /// <summary>
        /// 执行WL迭代,更新节点标签
        /// </summary>
        /// <param name="graph">CAD 2D图</param>
        /// <param name="iterations">迭代次数(默认3层)</param>
        /// <returns>每次迭代后的标签频率列表</returns>
        public static List<Dictionary<string, int>> PerformWLIterations(CADGraphEdgeGraph graph, int iterations = 3)
        {
            var labelFrequenciesPerIter = new List<Dictionary<string, int>>();
            
            if (graph == null || graph.Nodes.Count == 0)
            {
                Console.WriteLine("警告:空CAD图,无法执行WL迭代");
                return labelFrequenciesPerIter;
            }
        
            // 初始化所有节点的标签(基于边类型和几何特征)
            foreach (var node in graph.Nodes)
            {
                node.CurrentLabel = BuildInitialLabel(node);
            }
        
            // 统计初始迭代的标签频率(迭代0)
            labelFrequenciesPerIter.Add(CountLabelFrequencies(graph));
        
            // 执行WL迭代
            for (int iter = 1; iter <= iterations; iter++)
            {
                var newLabels = new Dictionary<int, string>();
        
                foreach (var node in graph.Nodes)
                {
                    // 获取邻居标签并排序
                    var neighborLabels = node.ConnectedNodes
                        .Where(nid => graph.Nodes.Any(n => n.Id == nid))
                        .Select(nid => graph.Nodes.First(n => n.Id == nid).CurrentLabel)
                        .OrderBy(l => l)
                        .ToList();
        
                    // 构建新标签:当前标签 + 邻居标签列表
                    var labelBuilder = new StringBuilder();
                    labelBuilder.Append($"[{node.CurrentLabel}]{string.Join(",", neighborLabels)}");
        
                    // 使用MD5生成新标签(压缩长度)
                    newLabels[node.Id] = HashLabel(labelBuilder.ToString());
                }
        
                // 更新所有节点标签
                foreach (var kvp in newLabels)
                {
                    var node = graph.Nodes.First(n => n.Id == kvp.Key);
                    node.CurrentLabel = kvp.Value;
                }
        
                // 统计当前迭代的标签频率
                labelFrequenciesPerIter.Add(CountLabelFrequencies(graph));
            }
        
            return labelFrequenciesPerIter;
        }

        /// <summary>
        /// 构建初始标签(基于边类型和几何特征)
        /// </summary>
        private static string BuildInitialLabel(CADGraphEdgeNode node)
        {
            var parts = new List<string>
            {
                node.EdgeType,
                node.IsHorizontal ? "H" : node.IsVertical ? "V" : "D",
                Math.Round(node.GeometryValue, 2).ToString()
            };
            
            if (node.Angle > 0)
            {
                parts.Add($"A{Math.Round(node.Angle, 1)}");
            }
            
            return string.Join("_", parts);
        }

        /// <summary>
        /// 哈希标签(使用MD5前8位)
        /// </summary>
        private static string HashLabel(string input)
        {
            using (var md5 = MD5.Create())
            {
                var bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
                return BitConverter.ToString(bytes, 0, 4).Replace("-", "").ToLower();
            }
        }

        /// <summary>
        /// 统计CAD图中各标签的出现频率
        /// </summary>
        private static Dictionary<string, int> CountLabelFrequencies(CADGraphEdgeGraph graph)
        {
            var frequency = new Dictionary<string, int>();
            
            foreach (var node in graph.Nodes)
            {
                if (!frequency.ContainsKey(node.CurrentLabel))
                {
                    frequency[node.CurrentLabel] = 0;
                }
                frequency[node.CurrentLabel]++;
            }
            
            return frequency;
        }

        /// <summary>
        /// 计算两个CAD图形的相似度(基于WL标签频率的余弦相似度)
        /// </summary>
        public static double CalculateSimilarity(
            Dictionary<string, int> freq1, 
            Dictionary<string, int> freq2,
            bool useCosine = true)
        {
            if (freq1.Count == 0 || freq2.Count == 0)
                return 0.0;

            if (useCosine)
            {
                return CalculateCosineSimilarity(freq1, freq2);
            }
            else
            {
                return CalculateJaccardSimilarity(freq1, freq2);
            }
        }

        /// <summary>
        /// 余弦相似度
        /// </summary>
        private static double CalculateCosineSimilarity(Dictionary<string, int> freq1, Dictionary<string, int> freq2)
        {
            // 获取所有标签的并集
            var allLabels = new HashSet<string>(freq1.Keys);
            allLabels.UnionWith(freq2.Keys);

            double dotProduct = 0;
            double norm1 = 0;
            double norm2 = 0;

            foreach (var label in allLabels)
            {
                int v1 = freq1.ContainsKey(label) ? freq1[label] : 0;
                int v2 = freq2.ContainsKey(label) ? freq2[label] : 0;

                dotProduct += v1 * v2;
                norm1 += v1 * v1;
                norm2 += v2 * v2;
            }

            if (norm1 == 0 || norm2 == 0)
                return 0.0;

            return dotProduct / (Math.Sqrt(norm1) * Math.Sqrt(norm2));
        }

        /// <summary>
        /// Jaccard相似度
        /// </summary>
        private static double CalculateJaccardSimilarity(Dictionary<string, int> freq1, Dictionary<string, int> freq2)
        {
            var intersection = new HashSet<string>(freq1.Keys);
            intersection.IntersectWith(freq2.Keys);

            var union = new HashSet<string>(freq1.Keys);
            union.UnionWith(freq2.Keys);

            return union.Count == 0 ? 0.0 : (double)intersection.Count / union.Count;
        }

        /// <summary>
        /// 批量计算多个CAD图形之间的相似度矩阵
        /// </summary>
        public static double[,] ComputeSimilarityMatrix(
            List<CADGraphEdgeGraph> graphs,
            int wlIterations = 3,
            double decayFactor = 0.5)
        {
            int n = graphs.Count;
            double[,] similarityMatrix = new double[n, n];

            Console.WriteLine($"\n开始计算 {n} 个CAD图形的相似度矩阵...");

            // 预先计算每个图形的WL迭代结果
            var allFrequencies = new List<List<Dictionary<string, int>>>();
            for (int i = 0; i < n; i++)
            {
                var frequencies = PerformWLIterations(graphs[i], iterations: wlIterations);
                allFrequencies.Add(frequencies);
                Console.WriteLine($"  ✓ 图形 {i + 1}/{n} 完成WL迭代");
            }

            // 计算相似度矩阵
            for (int i = 0; i < n; i++)
            {
                for (int j = i; j < n; j++)
                {
                    double similarity = CalculateMultiIterationSimilarity(
                        allFrequencies[i], 
                        allFrequencies[j], 
                        decayFactor);
                    
                    similarityMatrix[i, j] = similarity;
                    similarityMatrix[j, i] = similarity;
                }
            }

            return similarityMatrix;
        }

        /// <summary>
        /// 计算多轮迭代的综合相似度(带衰减因子)
        /// </summary>
        public static double CalculateMultiIterationSimilarity(
            List<Dictionary<string, int>> freqList1,
            List<Dictionary<string, int>> freqList2,
            double decayFactor = 0.5)
        {
            if (freqList1.Count == 0 || freqList2.Count == 0)
                return 0.0;

            int maxIterations = Math.Min(freqList1.Count, freqList2.Count);
            double totalSimilarity = 0.0;
            double totalWeight = 0.0;

            for (int i = 0; i < maxIterations; i++)
            {
                double weight = Math.Pow(decayFactor, i);
                double sim = CalculateSimilarity(freqList1[i], freqList2[i], useCosine: true);
                
                totalSimilarity += weight * sim;
                totalWeight += weight;
            }

            return totalSimilarity / totalWeight;
        }
    }
}

2. 创建CAD图形构建器

csharp 复制代码
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;

namespace cad_tools
{
    /// <summary>
    /// CAD图形构建器 - 从CAD文档提取2D图形特征
    /// </summary>
    public static class CADGraphEdgeBuilder
    {
        /// <summary>
        /// 从当前CAD文档构建图形
        /// </summary>
        /// <param name="acadDoc">CAD文档</param>
        /// <param name="graphName">图形名称(可选,默认为文件名)</param>
        /// <returns>CAD 2D图</returns>
        public static CADGraphEdgeGraph BuildGraphFromDocument(AcadDocument acadDoc, string graphName = "")
        {
            var graph = new CADGraphEdgeGraph
            {
                SourceFile = acadDoc.FullName,
                GraphName = string.IsNullOrEmpty(graphName) 
                    ? System.IO.Path.GetFileNameWithoutExtension(acadDoc.FullName) 
                    : graphName
            };

            try
            {
                // 获取模型空间中的所有实体
                var modelSpace = acadDoc.ModelSpace;
                int nodeId = 0;
                
                // 第一遍:创建所有节点
                var nodeMap = new Dictionary<object, CADGraphEdgeNode>();
                
                foreach (AcadEntity entity in modelSpace)
                {
                    var node = CreateNodeFromEntity(entity, nodeId++);
                    if (node != null)
                    {
                        graph.Nodes.Add(node);
                        nodeMap[entity] = node;
                    }
                }

                // 第二遍:建立连接关系(基于端点重合)
                BuildConnections(graph, nodeMap);

                Console.WriteLine($"✓ 成功构建CAD图形:{graph.GraphName},包含 {graph.Nodes.Count} 个节点");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"× 构建CAD图形失败:{ex.Message}");
            }

            return graph;
        }

        /// <summary>
        /// 从CAD实体创建节点
        /// </summary>
        private static CADGraphEdgeNode CreateNodeFromEntity(AcadEntity entity, int nodeId)
        {
            var node = new CADGraphEdgeNode
            {
                Id = nodeId
            };

            try
            {
                switch (entity)
                {
                    case AcadLine line:
                        node.EdgeType = "Line";
                        node.GeometryValue = CalculateLineLength(line);
                        node.IsHorizontal = Math.Abs(line.EndPoint[1] - line.StartPoint[1]) < 0.001;
                        node.IsVertical = Math.Abs(line.EndPoint[0] - line.StartPoint[0]) < 0.001;
                        node.Angle = CalculateLineAngle(line);
                        break;

                    case AcadArc arc:
                        node.EdgeType = "Arc";
                        node.GeometryValue = arc.Radius;
                        node.Angle = (arc.EndAngle - arc.StartAngle) * 180.0 / Math.PI;
                        break;

                    case AcadCircle circle:
                        node.EdgeType = "Circle";
                        node.GeometryValue = circle.Radius;
                        node.IsHorizontal = true;
                        node.IsVertical = true;
                        break;

                    case AcadLWPolyline polyline:
                        node.EdgeType = "Polyline";
                        node.GeometryValue = CalculatePolylineLength(polyline);
                        break;

                    case AcadEllipse ellipse:
                        node.EdgeType = "Ellipse";
                        node.GeometryValue = ellipse.MajorRadius;
                        break;

                    default:
                        return null; // 跳过不支持的实体类型
                }

                node.CurrentLabel = node.EdgeType;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"警告:无法解析实体:{ex.Message}");
                return null;
            }

            return node;
        }

        /// <summary>
        /// 建立连接关系(基于端点重合)
        /// </summary>
        private static void BuildConnections(CADGraphEdgeGraph graph, Dictionary<object, CADGraphEdgeNode> nodeMap)
        {
            double tolerance = 0.001; // 容差

            foreach (var nodeA in graph.Nodes)
            {
                foreach (var nodeB in graph.Nodes)
                {
                    if (nodeA.Id == nodeB.Id) continue;

                    if (AreConnected(nodeA, nodeB, tolerance))
                    {
                        if (!nodeA.ConnectedNodes.Contains(nodeB.Id))
                        {
                            nodeA.ConnectedNodes.Add(nodeB.Id);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 判断两个节点是否连接(需要具体实现端点检测)
        /// </summary>
        private static bool AreConnected(CADGraphEdgeNode nodeA, CADGraphEdgeNode nodeB, double tolerance)
        {
            // TODO: 实现端点重合检测逻辑
            // 这里需要根据实体类型获取端点坐标
            return false;
        }

        /// <summary>
        /// 计算直线长度
        /// </summary>
        private static double CalculateLineLength(AcadLine line)
        {
            double dx = line.EndPoint[0] - line.StartPoint[0];
            double dy = line.EndPoint[1] - line.StartPoint[1];
            double dz = line.EndPoint[2] - line.StartPoint[2];
            return Math.Sqrt(dx * dx + dy * dy + dz * dz);
        }

        /// <summary>
        /// 计算直线角度(相对于X轴)
        /// </summary>
        private static double CalculateLineAngle(AcadLine line)
        {
            double dx = line.EndPoint[0] - line.StartPoint[0];
            double dy = line.EndPoint[1] - line.StartPoint[1];
            double angle = Math.Atan2(dy, dx) * 180.0 / Math.PI;
            return angle < 0 ? angle + 360 : angle;
        }

        /// <summary>
        /// 计算多段线长度
        /// </summary>
        private static double CalculatePolylineLength(AcadLWPolyline polyline)
        {
            double length = 0;
            var coords = polyline.Coordinates;
            
            for (int i = 0; i < coords.Length - 2; i += 2)
            {
                double dx = coords[i + 2] - coords[i];
                double dy = coords[i + 3] - coords[i + 1];
                length += Math.Sqrt(dx * dx + dy * dy);
            }
            
            return length;
        }

        /// <summary>
        /// 批量构建文件夹中所有CAD文档的图形
        /// </summary>
        public static List<CADGraphEdgeGraph> BuildGraphsFromFolder(string folderPath)
        {
            var graphs = new List<CADGraphEdgeGraph>();
            
            if (!System.IO.Directory.Exists(folderPath))
            {
                Console.WriteLine($"错误:文件夹不存在:{folderPath}");
                return graphs;
            }

            var dwgFiles = System.IO.Directory.GetFiles(folderPath, "*.dwg");
            Console.WriteLine($"\n找到 {dwgFiles.Length} 个DWG文件");

            var acadApp = CadConnect.GetOrCreateInstance();
            if (acadApp == null)
            {
                Console.WriteLine("错误:无法连接到AutoCAD");
                return graphs;
            }

            foreach (var dwgFile in dwgFiles)
            {
                try
                {
                    Console.WriteLine($"\n处理:{System.IO.Path.GetFileName(dwgFile)}");
                    var doc = acadApp.Documents.Open(dwgFile, false, true);
                    var graph = BuildGraphFromDocument(doc, System.IO.Path.GetFileNameWithoutExtension(dwgFile));
                    graphs.Add(graph);
                    doc.Close(false);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"× 处理失败:{ex.Message}");
                }
            }

            return graphs;
        }
    }
}

3. 创建CAD标注数据库操作类(共享同一数据库)

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Linq;
using Newtonsoft.Json;

namespace cad_tools
{
    /// <summary>
    /// CAD标注数据库 - 共享topology_labels.db,但使用独立表
    /// </summary>
    public class CADDimensionDatabase
    {
        private readonly string _connectionString;
        private readonly string _dbPath;

        public CADDimensionDatabase(string dbPath = "topology_labels.db")
        {
            _dbPath = dbPath;
            _connectionString = $"Data Source={dbPath};Version=3;";
            InitializeDatabase();
        }

        /// <summary>
        /// 初始化CAD标注数据库表结构
        /// </summary>
        private void InitializeDatabase()
        {
            using (var connection = new SQLiteConnection(_connectionString))
            {
                connection.Open();
                
                using (var cmd = new SQLiteCommand("PRAGMA foreign_keys = ON;", connection))
                {
                    cmd.ExecuteNonQuery();
                }

                // CAD图形表
                string createCADGraphsTable = @"
                    CREATE TABLE IF NOT EXISTS cad_graphs (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        graph_name TEXT NOT NULL,
                        file_path TEXT NOT NULL,
                        view_name TEXT,
                        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                        UNIQUE(graph_name, file_path, view_name)
                    );";

                // CAD图节点表
                string createCADNodesTable = @"
                    CREATE TABLE IF NOT EXISTS cad_nodes (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        graph_id INTEGER NOT NULL,
                        node_id INTEGER NOT NULL,
                        edge_type TEXT NOT NULL,
                        geometry_value REAL,
                        angle REAL,
                        is_horizontal INTEGER DEFAULT 0,
                        is_vertical INTEGER DEFAULT 0,
                        FOREIGN KEY (graph_id) REFERENCES cad_graphs(id) ON DELETE CASCADE,
                        UNIQUE(graph_id, node_id)
                    );";

                // CAD图连接关系表
                string createCADEdgesTable = @"
                    CREATE TABLE IF NOT EXISTS cad_edges (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        graph_id INTEGER NOT NULL,
                        from_node INTEGER NOT NULL,
                        to_node INTEGER NOT NULL,
                        FOREIGN KEY (graph_id) REFERENCES cad_graphs(id) ON DELETE CASCADE
                    );";

                // CAD WL结果表
                string createCADWLResultsTable = @"
                    CREATE TABLE IF NOT EXISTS cad_wl_results (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        graph_id INTEGER NOT NULL,
                        iteration INTEGER NOT NULL,
                        label_frequencies TEXT NOT NULL,
                        FOREIGN KEY (graph_id) REFERENCES cad_graphs(id) ON DELETE CASCADE,
                        UNIQUE(graph_id, iteration)
                    );";

                // CAD标注规则表(存储学习到的标注规则)
                string createCADRulesTable = @"
                    CREATE TABLE IF NOT EXISTS cad_dimension_rules (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        graph_id INTEGER NOT NULL,
                        rule_name TEXT NOT NULL,
                        rule_type TEXT NOT NULL,
                        rule_pattern TEXT,
                        dimension_value TEXT,
                        dimension_type TEXT,
                        reference_nodes TEXT,
                        annotation_style TEXT,
                        confidence REAL DEFAULT 1.0,
                        notes TEXT,
                        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                        FOREIGN KEY (graph_id) REFERENCES cad_graphs(id) ON DELETE CASCADE
                    );";

                // 创建索引
                string createIndexes = @"
                    CREATE INDEX IF NOT EXISTS idx_cad_graph_name ON cad_graphs(graph_name);
                    CREATE INDEX IF NOT EXISTS idx_cad_wl_graph ON cad_wl_results(graph_id);
                    CREATE INDEX IF NOT EXISTS idx_cad_rule_type ON cad_dimension_rules(rule_type);
                ";

                using (var command = new SQLiteCommand(connection))
                {
                    command.CommandText = createCADGraphsTable;
                    command.ExecuteNonQuery();

                    command.CommandText = createCADNodesTable;
                    command.ExecuteNonQuery();

                    command.CommandText = createCADEdgesTable;
                    command.ExecuteNonQuery();

                    command.CommandText = createCADWLResultsTable;
                    command.ExecuteNonQuery();

                    command.CommandText = createCADRulesTable;
                    command.ExecuteNonQuery();

                    command.CommandText = createIndexes;
                    command.ExecuteNonQuery();
                }

                Console.WriteLine($"CAD标注数据库初始化完成:{_dbPath}");
            }
        }

        /// <summary>
        /// 保存CAD图形及其WL结果
        /// </summary>
        public int UpsertCADGraphWithWL(CADGraphEdgeGraph graph, List<Dictionary<string, int>> wlFrequencies)
        {
            using (var connection = new SQLiteConnection(_connectionString))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        // 插入或更新图形信息
                        int graphId = GetOrCreateCADGraph(connection, graph.GraphName, graph.SourceFile, "");
                        
                        // 保存节点信息
                        SaveNodes(connection, graphId, graph.Nodes, transaction);
                        
                        // 保存连接关系
                        SaveEdges(connection, graphId, graph.Nodes, transaction);
                        
                        // 删除旧的WL结果
                        string deleteOld = "DELETE FROM cad_wl_results WHERE graph_id = @graph_id";
                        using (var cmd = new SQLiteCommand(deleteOld, connection, transaction))
                        {
                            cmd.Parameters.AddWithValue("@graph_id", graphId);
                            cmd.ExecuteNonQuery();
                        }

                        // 保存WL结果
                        for (int iter = 0; iter < wlFrequencies.Count; iter++)
                        {
                            string insertWL = @"
                                INSERT INTO cad_wl_results (graph_id, iteration, label_frequencies) 
                                VALUES (@graph_id, @iteration, @frequencies)";

                            using (var cmd = new SQLiteCommand(insertWL, connection, transaction))
                            {
                                cmd.Parameters.AddWithValue("@graph_id", graphId);
                                cmd.Parameters.AddWithValue("@iteration", iter);
                                cmd.Parameters.AddWithValue("@frequencies", JsonConvert.SerializeObject(wlFrequencies[iter]));
                                cmd.ExecuteNonQuery();
                            }
                        }
                        
                        transaction.Commit();
                        Console.WriteLine($"✓ CAD图形 '{graph.GraphName}' 已存储({graph.Nodes.Count} 个节点)");
                        
                        return graphId;
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        Console.WriteLine($"× 存储CAD图形失败:{ex.Message}");
                        throw;
                    }
                }
            }
        }

        /// <summary>
        /// 添加标注规则
        /// </summary>
        public void AddDimensionRule(int graphId, string ruleName, string ruleType, 
            string dimensionValue, string dimensionType, string annotationStyle, 
            double confidence = 1.0, string notes = "")
        {
            using (var connection = new SQLiteConnection(_connectionString))
            {
                connection.Open();
                
                string insert = @"
                    INSERT INTO cad_dimension_rules (
                        graph_id, rule_name, rule_type, dimension_value, 
                        dimension_type, annotation_style, confidence, notes)
                    VALUES (@graph_id, @rule_name, @rule_type, @dimension_value,
                            @dimension_type, @annotation_style, @confidence, @notes)";

                using (var cmd = new SQLiteCommand(insert, connection))
                {
                    cmd.Parameters.AddWithValue("@graph_id", graphId);
                    cmd.Parameters.AddWithValue("@rule_name", ruleName);
                    cmd.Parameters.AddWithValue("@rule_type", ruleType);
                    cmd.Parameters.AddWithValue("@dimension_value", dimensionValue);
                    cmd.Parameters.AddWithValue("@dimension_type", dimensionType);
                    cmd.Parameters.AddWithValue("@annotation_style", annotationStyle);
                    cmd.Parameters.AddWithValue("@confidence", confidence);
                    cmd.Parameters.AddWithValue("@notes", notes);
                    cmd.ExecuteNonQuery();
                }

                Console.WriteLine($"✓ 已添加标注规则:{ruleName} = {dimensionValue}");
            }
        }

        /// <summary>
        /// 根据WL相似度查找推荐的标注规则
        /// </summary>
        public List<(string RuleName, string DimensionValue, string DimensionType, 
                     double Similarity, double Confidence, string AnnotationStyle)> 
            FindRecommendedRules(List<Dictionary<string, int>> wlFrequencies, 
                                 int topK = 10, 
                                 double minSimilarity = 0.5)
        {
            var results = new List<(string, string, string, double, double, string)>();
            
            if (wlFrequencies.Count == 0)
            {
                Console.WriteLine("警告:WL频率数据为空");
                return results;
            }

            int queryIteration = wlFrequencies.Count - 1;

            using (var connection = new SQLiteConnection(_connectionString))
            {
                connection.Open();
                
                // 获取所有已标注的CAD图形及其WL结果
                string query = @"
                    SELECT g.id, g.graph_name, dr.rule_name, dr.dimension_value, 
                           dr.dimension_type, dr.annotation_style, dr.confidence, 
                           wr.label_frequencies
                    FROM cad_graphs g
                    INNER JOIN cad_wl_results wr ON g.id = wr.graph_id
                    INNER JOIN cad_dimension_rules dr ON g.id = dr.graph_id
                    WHERE wr.iteration = @iteration
                    ORDER BY g.graph_name";

                var graphData = new Dictionary<string, (CADGraphEdgeWLData data, int graphId)>();

                using (var cmd = new SQLiteCommand(query, connection))
                {
                    cmd.Parameters.AddWithValue("@iteration", queryIteration);
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            int graphId = reader.GetInt32(0);
                            string graphName = reader.GetString(1);
                            string ruleName = reader.GetString(2);
                            string dimensionValue = reader.GetString(3);
                            string dimensionType = reader.GetString(4);
                            string annotationStyle = reader.GetString(5);
                            double confidence = reader.GetDouble(6);
                            string freqJson = reader.GetString(7);

                            var frequencies = JsonConvert.DeserializeObject<Dictionary<string, int>>(freqJson);
                            
                            if (frequencies == null) continue;

                            if (!graphData.ContainsKey(graphName))
                            {
                                graphData[graphName] = (new CADGraphEdgeWLData(), graphId);
                            }

                            if (graphData[graphName].data.WLFreqs.Count == 0)
                            {
                                graphData[graphName].data.WLFreqs.Add(frequencies);
                            }

                            graphData[graphName].data.Rules.Add(new CADRuleData(
                                ruleName, dimensionValue, dimensionType, 
                                annotationStyle, confidence));
                        }
                    }
                }

                // 计算相似度
                foreach (var kvp in graphData)
                {
                    string graphName = kvp.Key;
                    var (data, graphId) = kvp.Value;
                    
                    double similarity = CADWLGraphKernel.CalculateSimilarity(
                        wlFrequencies[queryIteration], 
                        data.WLFreqs[0]);
                    
                    if (similarity >= minSimilarity)
                    {
                        foreach (var rule in data.Rules)
                        {
                            results.Add((rule.RuleName, rule.DimensionValue, 
                                       rule.DimensionType, similarity, 
                                       rule.Confidence, rule.AnnotationStyle));
                        }
                    }
                }

                // 按相似度排序
                results = results
                    .OrderByDescending(r => r.Item4)
                    .ThenByDescending(r => r.Item5)
                    .Take(topK)
                    .ToList();
            }

            return results;
        }

        /// <summary>
        /// 获取或创建CAD图形记录
        /// </summary>
        private int GetOrCreateCADGraph(SQLiteConnection connection, 
                                       string graphName, 
                                       string filePath, 
                                       string viewName)
        {
            string select = "SELECT id FROM cad_graphs WHERE graph_name = @graph_name AND file_path = @file_path AND (view_name = @view_name OR (view_name IS NULL AND @view_name = ''))";
            using (var cmd = new SQLiteCommand(select, connection))
            {
                cmd.Parameters.AddWithValue("@graph_name", graphName);
                cmd.Parameters.AddWithValue("@file_path", filePath);
                cmd.Parameters.AddWithValue("@view_name", viewName);
                var result = cmd.ExecuteScalar();
                if (result != null)
                {
                    return Convert.ToInt32(result);
                }
            }

            string insert = @"
                INSERT INTO cad_graphs (graph_name, file_path, view_name) 
                VALUES (@graph_name, @file_path, @view_name)";
            
            using (var cmd = new SQLiteCommand(insert, connection))
            {
                cmd.Parameters.AddWithValue("@graph_name", graphName);
                cmd.Parameters.AddWithValue("@file_path", filePath);
                cmd.Parameters.AddWithValue("@view_name", string.IsNullOrEmpty(viewName) ? (object)DBNull.Value : viewName);
                cmd.ExecuteNonQuery();
                
                cmd.CommandText = "SELECT last_insert_rowid()";
                return Convert.ToInt32(cmd.ExecuteScalar());
            }
        }

        /// <summary>
        /// 保存节点信息
        /// </summary>
        private void SaveNodes(SQLiteConnection connection, int graphId, 
                              List<CADGraphEdgeNode> nodes, SQLiteTransaction transaction)
        {
            // 删除旧节点
            string deleteOld = "DELETE FROM cad_nodes WHERE graph_id = @graph_id";
            using (var cmd = new SQLiteCommand(deleteOld, connection, transaction))
            {
                cmd.Parameters.AddWithValue("@graph_id", graphId);
                cmd.ExecuteNonQuery();
            }

            // 插入新节点
            foreach (var node in nodes)
            {
                string insert = @"
                    INSERT INTO cad_nodes (graph_id, node_id, edge_type, geometry_value, 
                                          angle, is_horizontal, is_vertical)
                    VALUES (@graph_id, @node_id, @edge_type, @geometry_value,
                            @angle, @is_horizontal, @is_vertical)";

                using (var cmd = new SQLiteCommand(insert, connection, transaction))
                {
                    cmd.Parameters.AddWithValue("@graph_id", graphId);
                    cmd.Parameters.AddWithValue("@node_id", node.Id);
                    cmd.Parameters.AddWithValue("@edge_type", node.EdgeType);
                    cmd.Parameters.AddWithValue("@geometry_value", node.GeometryValue);
                    cmd.Parameters.AddWithValue("@angle", node.Angle);
                    cmd.Parameters.AddWithValue("@is_horizontal", node.IsHorizontal ? 1 : 0);
                    cmd.Parameters.AddWithValue("@is_vertical", node.IsVertical ? 1 : 0);
                    cmd.ExecuteNonQuery();
                }
            }
        }

        /// <summary>
        /// 保存连接关系
        /// </summary>
        private void SaveEdges(SQLiteConnection connection, int graphId,
                              List<CADGraphEdgeNode> nodes, SQLiteTransaction transaction)
        {
            string deleteOld = "DELETE FROM cad_edges WHERE graph_id = @graph_id";
            using (var cmd = new SQLiteCommand(deleteOld, connection, transaction))
            {
                cmd.Parameters.AddWithValue("@graph_id", graphId);
                cmd.ExecuteNonQuery();
            }

            foreach (var node in nodes)
            {
                foreach (var connectedId in node.ConnectedNodes)
                {
                    string insert = @"
                        INSERT INTO cad_edges (graph_id, from_node, to_node)
                        VALUES (@graph_id, @from_node, @to_node)";

                    using (var cmd = new SQLiteCommand(insert, connection, transaction))
                    {
                        cmd.Parameters.AddWithValue("@graph_id", graphId);
                        cmd.Parameters.AddWithValue("@from_node", node.Id);
                        cmd.Parameters.AddWithValue("@to_node", connectedId);
                        cmd.ExecuteNonQuery();
                    }
                }
            }
        }
    }

    /// <summary>
    /// CAD图形WL数据辅助类
    /// </summary>
    public class CADGraphEdgeWLData
    {
        public List<Dictionary<string, int>> WLFreqs { get; set; } = new List<Dictionary<string, int>>();
        public List<CADRuleData> Rules { get; set; } = new List<CADRuleData>();
    }

    /// <summary>
    /// CAD标注规则数据
    /// </summary>
    public class CADRuleData
    {
        public string RuleName { get; set; }
        public string DimensionValue { get; set; }
        public string DimensionType { get; set; }
        public string AnnotationStyle { get; set; }
        public double Confidence { get; set; }

        public CADRuleData(string ruleName, string dimensionValue, string dimensionType,
                          string annotationStyle, double confidence)
        {
            RuleName = ruleName;
            DimensionValue = dimensionValue;
            DimensionType = dimensionType;
            AnnotationStyle = annotationStyle;
            Confidence = confidence;
        }
    }
}

4. 创建使用示例

csharp 复制代码
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Interop;

namespace cad_tools
{
    /// <summary>
    /// CAD WL学习示例
    /// </summary>
    public static class CADWLExamples
    {
        /// <summary>
        /// 示例1:学习已有标注的图纸
        /// </summary>
        public static void LearnFromAnnotatedDrawing(string dwgPath)
        {
            Console.WriteLine("\n========== CAD特征学习示例 ==========\n");
            
            // 1. 连接到CAD
            var acadApp = CadConnect.GetOrCreateInstance();
            if (acadApp == null)
            {
                Console.WriteLine("错误:无法连接到AutoCAD");
                return;
            }

            // 2. 打开图纸
            Console.WriteLine($"打开图纸:{dwgPath}");
            var doc = acadApp.Documents.Open(dwgPath, false, false);

            // 3. 构建图形
            Console.WriteLine("\n构建图形特征...");
            var graph = CADGraphEdgeBuilder.BuildGraphFromDocument(doc, "示例图形");

            // 4. 执行WL迭代
            Console.WriteLine("\n执行WL迭代...");
            var wlFreq = CADWLGraphKernel.PerformWLIterations(graph, iterations: 3);
            
            // 5. 保存到数据库
            var database = new CADDimensionDatabase();
            int graphId = database.UpsertCADGraphWithWL(graph, wlFreq);

            // 6. 添加标注规则(这里需要手动输入或从图纸提取)
            Console.WriteLine("\n添加标注规则...");
            database.AddDimensionRule(graphId, 
                ruleName: "高度标注",
                ruleType: "linear",
                dimensionValue: "27.30",
                dimensionType: "垂直尺寸",
                annotationStyle: "默认",
                confidence: 1.0,
                notes: "学习自示例图纸");

            database.AddDimensionRule(graphId,
                ruleName: "宽度标注",
                ruleType: "linear",
                dimensionValue: "12.80",
                dimensionType: "水平尺寸",
                annotationStyle: "默认",
                confidence: 1.0,
                notes: "学习自示例图纸");

            doc.Close(false);
            Console.WriteLine("\n✓ 学习完成!");
        }

        /// <summary>
        /// 示例2:根据已有图纸推荐标注
        /// </summary>
        public static void RecommendDimensionsForNewDrawing(string newDwgPath)
        {
            Console.WriteLine("\n========== CAD标注推荐示例 ==========\n");
            
            var acadApp = CadConnect.GetOrCreateInstance();
            if (acadApp == null) return;

            Console.WriteLine($"打开新图纸:{newDwgPath}");
            var doc = acadApp.Documents.Open(newDwgPath, false, true);

            // 构建图形
            var graph = CADGraphEdgeBuilder.BuildGraphFromDocument(doc, "新图形");
            var wlFreq = CADWLGraphKernel.PerformWLIterations(graph, iterations: 3);

            // 查询推荐规则
            var database = new CADDimensionDatabase();
            var recommendations = database.FindRecommendedRules(wlFreq, topK: 10, minSimilarity: 0.5);

            Console.WriteLine($"\n找到 {recommendations.Count} 条推荐标注规则:\n");
            
            for (int i = 0; i < Math.Min(5, recommendations.Count); i++)
            {
                var (ruleName, dimValue, dimType, similarity, confidence, style) = recommendations[i];
                Console.WriteLine($"推荐 {i + 1}:");
                Console.WriteLine($"  规则:{ruleName}");
                Console.WriteLine($"  标注值:{dimValue}");
                Console.WriteLine($"  类型:{dimType}");
                Console.WriteLine($"  相似度:{similarity:F3} ({similarity * 100:F1}%)");
                Console.WriteLine($"  置信度:{confidence:F2}");
                Console.WriteLine();
            }

            doc.Close(false);
        }

        /// <summary>
        /// 示例3:批量学习文件夹中的图纸
        /// </summary>
        public static void BatchLearnFromFolder(string folderPath)
        {
            Console.WriteLine($"\n========== 批量学习:{folderPath} ==========\n");
            
            var graphs = CADGraphEdgeBuilder.BuildGraphsFromFolder(folderPath);
            var database = new CADDimensionDatabase();

            foreach (var graph in graphs)
            {
                Console.WriteLine($"\n处理:{graph.GraphName}");
                var wlFreq = CADWLGraphKernel.PerformWLIterations(graph, iterations: 3);
                database.UpsertCADGraphWithWL(graph, wlFreq);
            }

            Console.WriteLine($"\n✓ 批量学习完成!共处理 {graphs.Count} 个图形");
        }

        /// <summary>
        /// 示例4:计算图形相似度矩阵
        /// </summary>
        public static void ComputeSimilarityMatrix(string folderPath)
        {
            Console.WriteLine("\n========== 计算相似度矩阵 ==========\n");
            
            var graphs = CADGraphEdgeBuilder.BuildGraphsFromFolder(folderPath);
            var matrix = CADWLGraphKernel.ComputeSimilarityMatrix(graphs, wlIterations: 3, decayFactor: 0.5);

            Console.WriteLine("\n相似度矩阵:\n");
            Console.Write("".PadRight(20));
            for (int j = 0; j < graphs.Count; j++)
            {
                Console.Write($"{graphs[j].GraphName.Substring(0, Math.Min(10, graphs[j].GraphName.Length))}".PadRight(15));
            }
            Console.WriteLine();

            for (int i = 0; i < graphs.Count; i++)
            {
                Console.Write($"{graphs[i].GraphName.Substring(0, Math.Min(10, graphs[i].GraphName.Length))}".PadRight(20));
                for (int j = 0; j < graphs.Count; j++)
                {
                    Console.Write($"{matrix[i, j]:F3}".PadRight(15));
                }
                Console.WriteLine();
            }
        }
    }
}

创建目录结构

bash 复制代码
share/cad/wl_learning/
├── cad_wl_graph_kernel.cs          # CAD WL图核实现
├── cad_graph_builder.cs             # CAD图形构建器
├── cad_dimension_database.cs        # CAD标注数据库(共享topology_labels.db)
└── cad_wl_examples.cs               # 使用示例

使用说明

这个CAD WL学习模块与SolidWorks的WL系统:

独立的部分

  • 完全独立的命名空间 cad_tools
  • 独立的类和方法,不依赖SolidWorks API
  • 独立的图形数据结构(基于2D边而非3D面)

共享的部分

  • 使用同一个 topology_labels.db 数据库
  • 独立的表结构(cad_graphs, cad_nodes, cad_edges, cad_wl_results, cad_dimension_rules
  • 互不干扰,各自管理自己的数据

使用流程

  1. 学习阶段:用已标注的图纸训练,提取图形特征和标注规则
  2. 推荐阶段:新图纸输入,通过WL相似度匹配,推荐标注规则
  3. 标注阶段:根据推荐自动添加尺寸标注

你可以直接用这些代码来学习你图中的标注样式!

复制代码
相关推荐
hughnz4 小时前
Palantir Technologies公司的竞争格局
人工智能·microsoft
陈天伟教授4 小时前
智能体架构:大语言模型驱动的自主系统深度解析与演进研究(一)
人工智能·语言模型·架构
R²AIN SUITE4 小时前
AI 智能体重构医药价值链:研发 / 临床 / 供应链三大场景深度落地与量化收益
人工智能
YuanDaima20484 小时前
基于 LangChain 1.0 的检索增强生成(RAG)实战
人工智能·笔记·python·langchain·个人开发·langgraph
大力财经4 小时前
纳米漫剧流水线接入满血版Seedance 2.0 实现工业级AI漫剧确定性交付
大数据·人工智能
咚咚王者4 小时前
人工智能之语音领域 语音处理 第六章 语音处理技术发展趋势与未来展望
人工智能·语音识别
ipython_harley4 小时前
【AGI】OpenAI核心贡献者翁家翌:修Infra的人,正在定义GPT-5
人工智能·gpt·ai·agi
幻风_huanfeng4 小时前
人工智能之数学基础:什么是凸优化问题?
人工智能·算法·机器学习·凸优化