用pywin32连接autocad 写一个利用遗传算法从选择的闭合图形内进行最优利用率的排版 ai草稿

好的,我们来深入细说遗传算法(Genetic Algorithm, GA)在钣金自动排版中的应用。

遗传算法 (GA) 在钣金排版中的详细解析

遗传算法是一种受达尔文生物进化论启发的元启发式优化算法。它不追求一次性找到数学上的绝对最优解,而是通过模拟“物竞天择,适者生存”的自然过程,在庞大的搜索空间中高效地寻找一个非常接近最优的、实用的解决方案。这对于零件形状各异、数量众多、约束复杂的钣金排料问题尤其有效。

核心原理与工作流程

可以将整个排料方案看作一个“生命体”(个体),而构成这个方案的各个要素(如零件的摆放顺序、旋转角度、起始坐标等)就是它的“基因”。GA 通过多代的演化来不断改进这些“生命体”。

  1. 编码 (Encoding):

    • 目的: 将现实世界的排料方案转换成计算机可以处理的“染色体”(一串数字或符号)。
    • 方法: 在排料中,常见的编码方式有:
      • 顺序编码: 染色体表示零件的下料顺序。例如,[3, 1, 5, 2, 4] 表示先放第3个零件,然后是第1个,依此类推。放置规则(如左下角填充法)决定了每个零件的具体位置。
      • 位置编码: 染色体直接包含每个零件的关键参数,如 (零件ID, X坐标, Y坐标, 旋转角度) 的组合。这种方式更直接但维度更高。
    • 关键: 编码必须能唯一且完整地描述一个排料方案。
  2. 初始化种群 (Initialization):

    • 算法开始时,随机生成一组(称为“种群”,Population)不同的排料方案作为第一代。种群大小(如50、100个个体)是一个重要参数。
  3. 适应度评估 (Fitness Evaluation):

    • 核心指标: 这是驱动进化的“裁判”。对于排料问题,最直接的适应度函数通常是 材料利用率
    • 计算公式: 利用率 = (所有零件总面积 / 所用板材面积) × 100%
    • 有时也会结合其他因素,如切割路径长度、工艺约束(桥位、微连接)等,形成复合适应度函数。
    • 适应度值越高的个体(即利用率越高的排料方案),在下一代中被选中的概率就越大。
  4. 选择 (Selection):

    • 目的: 从当前种群中挑选出优秀的“父母”个体,用于繁殖下一代。
    • 常用方法:
      • 轮盘赌选择 (Roulette Wheel Selection): 适应度越高的个体,被选中的“扇形区域”就越大,概率越高。
      • 锦标赛选择 (Tournament Selection): 随机选取几个个体进行“比赛”,胜者(适应度最高者)被选中。重复此过程直到选出足够数量的父母。
    • 原则: “优胜劣汰”,保证优良基因得以传承。
  5. 交叉 (Crossover / Recombination):

    • 目的: 模拟生物交配,将两个“父母”个体的基因进行重组,产生新的“后代”个体,期望继承双方的优点。
    • 排料中的挑战: 直接交叉可能会产生非法或低效的方案(如零件重叠、超出板幅)。
    • 常用策略(以顺序编码为例):
      • 顺序交叉 (Order Crossover, OX): 随机选取父母A的一段基因序列,复制到后代;然后按顺序从父母B中取剩余零件,填满后代。这能在一定程度上保持顺序信息。
      • 部分映射交叉 (Partially Mapped Crossover, PMX): 更复杂,能更好地处理顺序约束。
    • 结果: 产生一个或多个新的排料方案(后代)。
  6. 变异 (Mutation):

    • 目的: 模拟自然界基因突变,引入新的基因多样性,防止算法过早收敛到局部最优(即陷入一个不是最好的“小高峰”)。
    • 方法:
      • 交换变异: 随机交换染色体中两个基因的位置。例如,将顺序 [3, 1, 5, 2, 4] 变为 [3, 2, 5, 1, 4]
      • 插入变异: 随机取出一个基因,插入到另一个随机位置。
      • 逆转变异: 随机选取一段基因,将其顺序反转。
    • 关键参数: 变异概率通常很低(如1%-5%),避免破坏已有的优良结构。
  7. 迭代与终止 (Iteration and Termination):

    • 将经过选择、交叉、变异产生的新“后代”群体作为下一代种群。
    • 重复执行 评估 → 选择 → 交叉 → 变异 的循环。
    • 终止条件: 当达到预设的代数、适应度值在连续多代内不再显著提升、或找到了满意的解时,算法停止。
    • 输出: 最终种群中适应度最高的那个个体,即为算法找到的最佳排料方案。
优势详解
  • 强大的全局搜索能力: GA 不是从单点开始搜索,而是维护一个种群,相当于在搜索空间的多个点同时探索。这大大增加了找到全局最优解的可能性,而不是像一些贪心算法那样容易卡在某个局部最优。
  • 对问题依赖性低: 只要能定义出适应度函数,GA 就可以应用。它不关心问题内部的数学细节(如是否线性、连续),因此非常灵活。
  • 并行性好: 种群中每个个体的适应度评估可以独立进行,非常适合并行计算,加速求解过程。
  • 适合复杂组合优化: 排料问题是典型的NP-hard问题,随着零件数量增加,可能的排列组合呈指数级增长。GA 能在合理时间内找到高质量的近似解。
应用实例与局限性
  • 应用: 如您提到的,CNCkad 是成功应用GA的商业软件典范。许多学术研究也基于GA进行改进,例如:
    • 混合遗传算法: 将GA与其他算法(如模拟退火、局部搜索)结合,利用GA进行全局探索,用其他算法在局部进行精细调整,进一步提升性能。
    • 自适应遗传算法: 动态调整交叉和变异概率,提高收敛速度和精度。
  • 局限性:
    • 计算时间: 对于大规模问题,可能需要较长时间才能收敛。
    • 参数敏感: 种群大小、交叉/变异概率等参数的选择对性能影响较大,需要经验或调参。
    • 不一定是最优解: 它提供的是一个非常好的近似解,但不能保证是数学上的绝对最优。

总而言之,遗传算法通过模拟自然界的进化机制,将排料这个复杂的优化问题转化为一个“进化”过程。它通过不断地“试错”和“优选”,最终进化出材料利用率极高的排料方案,是现代智能排料软件背后的核心引擎之一。







好的,这是一个非常有挑战性且实用的项目!我们将使用 pywin32 连接 AutoCAD,并实现一个基于遗传算法(GA)的简单排版程序,目标是将一组矩形零件尽可能高效地排列在一个大的闭合区域内。

重要说明:

  1. 简化模型: 真实的工业级排料极其复杂。本示例将进行重大简化
    • 零件仅为矩形
    • 区域为凸多边形或矩形(非凸区域处理更复杂)。
    • 不考虑旋转(或仅允许90度旋转)。
    • 使用简单的“左下角”放置策略。
    • GA 编码为零件下料顺序
  2. 依赖库:
    • pywin32:连接 AutoCAD。
    • numpy:数值计算。
    • random:随机数生成。
    • typing:类型提示。

步骤 1: 环境准备

确保已安装:

bash

深色版本

pip install pywin32 numpy

步骤 2: Python 脚本 (ga_nesting_autocad.py)

python

深色版本

import win32com.client
import numpy as np
import random
from typing import List, Tuple, Dict
import pythoncom  # For COM threading# --- 配置参数 ---
POPULATION_SIZE = 50     # 种群大小
NUM_GENERATIONS = 100    # 迭代代数
MUTATION_RATE = 0.05     # 变异概率
CROSSOVER_RATE = 0.8     # 交叉概率class Rectangle:"""表示一个矩形零件"""def __init__(self, width: float, height: float, id: int):self.width = widthself.height = heightself.id = id# 如果允许旋转,可以添加旋转状态self.rotated = False  # 简化:不旋转def area(self) -> float:return self.width * self.heightclass NestingArea:"""表示排料区域(凸多边形)"""def __init__(self, vertices: List[Tuple[float, float]]):self.vertices = np.array(vertices)self.bounds = self._calculate_bounds()def _calculate_bounds(self) -> Tuple[float, float, float, float]:"""计算区域的包围盒 (min_x, min_y, max_x, max_y)"""min_x = np.min(self.vertices[:, 0])min_y = np.min(self.vertices[:, 1])max_x = np.max(self.vertices[:, 0])max_y = np.max(self.vertices[:, 1])return (min_x, min_y, max_x, max_y)def contains_point(self, x: float, y: float) -> bool:"""简化:检查点是否在区域的包围盒内。真实应用需要使用射线投射法(Ray Casting)或Winding Number算法检查是否在多边形内。此处为简化,仅检查包围盒。"""min_x, min_y, max_x, max_y = self.boundsreturn min_x <= x <= max_x and min_y <= y <= max_ydef area(self) -> float:"""简化:使用包围盒面积作为区域面积。真实应用应计算多边形面积。"""min_x, min_y, max_x, max_y = self.boundsreturn (max_x - min_x) * (max_y - min_y)class NestingGA:def __init__(self, parts: List[Rectangle], area: NestingArea):self.parts = partsself.area = areaself.total_part_area = sum(part.area() for part in parts)# 检查零件总面积是否超过区域面积(简化检查)if self.total_part_area > area.area():raise ValueError("零件总面积超过排料区域面积!")def _place_parts(self, order: List[int]) -> List[Tuple[float, float]]:"""根据给定的零件顺序,使用简单的"左下角"策略放置零件。返回每个零件左下角的坐标列表。"""placed_positions = []  # 存储已放置零件的 (x, y, width, height)part_positions = []    # 存储每个零件的放置位置 (x, y)# 将顺序映射到零件对象ordered_parts = [self.parts[i] for i in order]for part in ordered_parts:# 简单策略:从 (min_x, min_y) 开始,尝试放置min_x, min_y, max_x, max_y = self.area.boundsplaced = False# 简化:只尝试从左下角开始,逐行扫描(效率很低,仅演示)# 真实算法会使用更智能的空闲区域管理(如最大矩形算法)for y in np.arange(min_y, max_y, 1.0):  # 步长1mmfor x in np.arange(min_x, max_x, 1.0):if self._can_place(part, x, y, placed_positions):placed_positions.append((x, y, part.width, part.height))part_positions.append((x, y))placed = Truebreakif placed:breakif not placed:# 放不下,返回部分放置结果(或标记为无效)print(f"警告: 零件 {part.id} 无法放置!")part_positions.append((0, 0))  # 占位符return part_positionsdef _can_place(self, part: Rectangle, x: float, y: float, placed_positions: List[Tuple[float, float, float, float]]) -> bool:"""检查零件是否可以在 (x, y) 处放置。检查:1. 是否在区域内 2. 是否与已放置零件重叠"""# 检查左下角和右上角是否在区域内(简化)if (not self.area.contains_point(x, y) or not self.area.contains_point(x + part.width, y + part.height)):return False# 检查是否与已放置零件重叠for px, py, pw, ph in placed_positions:if (x < px + pw and x + part.width > px and y < py + ph and y + part.height > py):return Falsereturn Truedef fitness(self, individual: List[int]) -> float:"""适应度函数:计算材料利用率。individual: 零件下料顺序的索引列表"""positions = self._place_parts(individual)# 简化:假设所有零件都能放完# 真实情况需要计算实际放置的零件面积# 这里直接使用总面积(因为我们在 _place_parts 中尝试放置所有零件)# 更好的做法是返回实际利用率# 为了演示,我们假设放置成功# 实际利用率 = 实际放置零件面积 / 区域面积# 但此处简化为总零件面积 / 区域面积,如果放不下会降低适应度# 这是一个非常粗糙的近似if len(positions) != len(self.parts):return 0.0  # 放不下任何零件,适应度为0# 检查是否有零件被放置在无效位置(占位符)if any(pos == (0, 0) for pos in positions):return 0.1  # 惩罚,但不是0utilization = self.total_part_area / self.area.area()return utilizationdef create_individual(self) -> List[int]:"""创建一个个体(随机的零件顺序)"""order = list(range(len(self.parts)))random.shuffle(order)return orderdef create_population(self) -> List[List[int]]:"""创建初始种群"""return [self.create_individual() for _ in range(POPULATION_SIZE)]def selection(self, population: List[List[int]], fitnesses: List[float]) -> List[List[int]]:"""轮盘赌选择"""total_fitness = sum(fitnesses)if total_fitness == 0:# 所有个体适应度为0,随机选择return random.choices(population, k=POPULATION_SIZE)probabilities = [f / total_fitness for f in fitnesses]return random.choices(population, weights=probabilities, k=POPULATION_SIZE)def crossover(self, parent1: List[int], parent2: List[int]) -> Tuple[List[int], List[int]]:"""顺序交叉 (OX)"""if random.random() > CROSSOVER_RATE:return parent1[:], parent2[:]size = len(parent1)# 随机选择交叉点start, end = sorted(random.sample(range(size), 2))# 创建子代child1 = [-1] * sizechild2 = [-1] * size# 复制父代片段child1[start:end] = parent1[start:end]child2[start:end] = parent2[start:end]# 填充剩余位置,保持顺序def fill_child(child, parent_source):pointer = endfor i in range(end, end + size):idx = i % sizeval = parent_source[idx]if val not in child:child[pointer % size] = valpointer += 1fill_child(child1, parent2)fill_child(child2, parent1)return child1, child2def mutate(self, individual: List[int]) -> List[int]:"""交换变异"""if random.random() < MUTATION_RATE:i, j = random.sample(range(len(individual)), 2)individual[i], individual[j] = individual[j], individual[i]return individualdef run(self) -> Tuple[List[int], float]:"""运行遗传算法"""population = self.create_population()best_individual = Nonebest_fitness = 0.0for generation in range(NUM_GENERATIONS):# 计算适应度fitnesses = [self.fitness(ind) for ind in population]# 找到当前代最佳max_fitness = max(fitnesses)if max_fitness > best_fitness:best_fitness = max_fitnessbest_individual = population[fitnesses.index(max_fitness)]print(f"第 {generation+1} 代, 最佳利用率: {best_fitness:.4f}")# 选择selected = self.selection(population, fitnesses)# 交叉和变异new_population = []for i in range(0, POPULATION_SIZE, 2):parent1 = selected[i]parent2 = selected[i+1] if (i+1) < POPULATION_SIZE else selected[0]child1, child2 = self.crossover(parent1, parent2)child1 = self.mutate(child1)child2 = self.mutate(child2)new_population.extend([child1, child2])population = new_populationreturn best_individual, best_fitnessdef get_selection_from_autocad() -> Tuple[win32com.client.CDispatch, List, List]:"""连接AutoCAD,获取用户选择的闭合多段线(区域)和矩形(零件)。返回: (acad, area_polyline, part_rectangles)"""try:acad = win32com.client.Dispatch("AutoCAD.Application")doc = acad.ActiveDocumentmsp = doc.ModelSpace# 提示用户选择print("请在AutoCAD中选择一个闭合多段线作为排料区域,然后选择所有矩形零件。")selection = doc.Utility.GetSelection()area_polyline = Nonepart_rectangles = []for entity in selection:if entity.ObjectName == "AcDbPolyline" and entity.Closed:if area_polyline is None:area_polyline = entityprint(f"已选择区域: {entity.Handle}")else:print("警告: 发现多个闭合多段线,仅使用第一个。")elif entity.ObjectName == "AcDbRectangle":part_rectangles.append(entity)print(f"已选择零件: {entity.Handle}")else:print(f"忽略对象: {entity.ObjectName}")if not area_polyline:raise ValueError("未选择有效的闭合多段线作为排料区域!")if not part_rectangles:raise ValueError("未选择任何矩形零件!")return acad, area_polyline, part_rectanglesexcept Exception as e:print(f"获取AutoCAD选择时出错: {e}")raisedef extract_vertices(polyline) -> List[Tuple[float, float]]:"""从AutoCAD多段线提取顶点坐标"""vertices = []# 多段线的坐标存储为 [x1, y1, x2, y2, ...]coords = polyline.Coordinatesfor i in range(0, len(coords), 2):vertices.append((coords[i], coords[i+1]))return verticesdef extract_part_dimensions(rectangle) -> Tuple[float, float]:"""从AutoCAD矩形提取宽度和高度"""# 矩形通常有 Length 和 Width 属性# 或者通过角点计算try:width = rectangle.Widthheight = rectangle.Heightreturn width, heightexcept:# 如果属性不可用,尝试通过几何计算# 这里简化处理raise NotImplementedError("无法获取矩形尺寸")def draw_result_in_autocad(acad, best_order: List[int], parts: List[Rectangle], area_vertices: List[Tuple[float, float]], part_positions: List[Tuple[float, float]]):"""在AutoCAD中绘制排料结果。在实际中,best_order 和 part_positions 来自 _place_parts 的结果。"""doc = acad.ActiveDocumentmsp = doc.ModelSpace# 可选:清除旧结果或创建新图层try:result_layer = doc.Layers.Item("Nesting_Result")except:result_layer = doc.Layers.Add("Nesting_Result")msp.AddLightWeightPolyline([coord for vertex in area_vertices for coord in vertex]).Layer = "Nesting_Result"# 绘制放置好的零件for i, (x, y) in enumerate(part_positions):part = parts[best_order[i]]  # 注意顺序if (x, y) != (0, 0):  # 避开占位符# 绘制矩形rect = msp.AddLightWeightPolyline([x, y,x + part.width, y,x + part.width, y + part.height,x, y + part.height,x, y])rect.Layer = "Nesting_Result"# 添加文本标签text = msp.AddText(f"P{part.id}", win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, (x, y)), 2.0)text.Layer = "Nesting_Result"def main():"""主函数"""try:# 1. 连接AutoCAD并获取选择acad, area_polyline, part_rectangles = get_selection_from_autocad()# 2. 提取数据area_vertices = extract_vertices(area_polyline)nesting_area = NestingArea(area_vertices)parts = []for i, rect in enumerate(part_rectangles):width, height = extract_part_dimensions(rect)part = Rectangle(width, height, i)parts.append(part)print(f"排料区域: {len(area_vertices)} 个顶点")print(f"零件数量: {len(parts)}")# 3. 运行遗传算法nesting_ga = NestingGA(parts, nesting_area)best_order, best_utilization = nesting_ga.run()print(f"优化完成!最佳利用率: {best_utilization:.4f}")print(f"最佳下料顺序: {best_order}")# 4. 计算最佳顺序下的实际放置位置# 注意:这里应该用 best_order 调用 _place_parts# 但 _place_parts 是私有方法,我们可以重构或直接调用# 为了演示,我们假设 nesting_ga 有一个方法final_positions = nesting_ga._place_parts(best_order)# 5. 将结果绘制回AutoCADdraw_result_in_autocad(acad, best_order, parts, area_vertices, final_positions)print("排料结果已绘制到AutoCAD图层 'Nesting_Result'。")except Exception as e:print(f"程序执行出错: {e}")if __name__ == "__main__":main()

使用步骤

  1. 打开 AutoCAD 并创建一个新图纸。
  2. 绘制一个闭合的多段线 (PLINE) 作为排料区域。
  3. 绘制若干矩形 (RECTANG) 作为待排料的零件。
  4. 运行 Python 脚本
    bash

    深色版本

    python ga_nesting_autocad.py
  5. 脚本会提示你选择对象,先选择区域多段线,再选择所有矩形零件,然后按 Enter。
  6. 脚本运行 GA 优化,并在控制台输出每代的最佳利用率。
  7. 优化完成后,结果会绘制在名为 Nesting_Result 的新图层上。

局限性与改进方向

  • 放置算法太简单: _place_parts 的扫描方式效率极低。应实现最大矩形算法 (Maximal Rectangles) 或最低水平线算法 (Bottom-Left)
  • 区域检查不准确: contains_point 仅检查包围盒。应实现射线投射法
  • 零件类型有限: 仅支持矩形。可扩展为支持多边形。
  • 无旋转: 可添加旋转状态到 Rectangle 类。
  • 性能: 对于大量零件,速度会很慢。可考虑并行计算适应度。
  • 错误处理: 需要更完善的错误处理和用户交互。

这个脚本提供了一个概念验证 (POC),展示了如何将 GA 与 AutoCAD 集成。要达到工业级水平,需要在此基础上进行大量复杂的算法和工程优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96390.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言io.Copy深度解析:高效数据复制的终极指南

在日常开发中&#xff0c;我们经常需要在不同的数据源之间复制数据。无论是文件操作、网络传输还是进程通信&#xff0c;数据复制都是不可或缺的基础操作。Go语言的标准库提供了一个强大而高效的工具来简化这一过程&#xff1a;io.Copy。 什么是io.Copy&#xff1f; io.Copy是G…

【Vue3】07-利用setup编写vue(2)-setup的语法糖

其它篇章&#xff1a; 1.【Vue3】01-创建Vue3工程 2.【Vue3】02-Vue3工程目录分析 3.【Vue3】03-编写app组件——src 4.【Vue3】04-编写vue实现一个简单效果 5.【Vue3】05-Options API和Composition API的区别 6.【Vue3】06-利用setup编写vue&#xff08;1&#xff09; 7.【Vue…

Firefox自定义备忘

1.设置firefox右键点击标签直接关闭&#xff0c;由于目前没有插件能实现这个功能&#xff0c;只能手动设置了&#xff08;目前已知支持142和之前的版本&#xff09; firefox117右键关闭macWin 117版本应该可以了&#xff0c;大家可试下&#xff0c;配置方法参考之前的帖子&…

跨屏互联KuapingCMS建站系统发布更新 增加数据看板

跨屏互联KuapingCMS建站系统发布更新&#xff0c;增加了文章统计、产品统计、软文统计、流量统计、pv统计、ip统计、os访问者设备统计等等&#xff0c;整个体验会更好&#xff0c;数据显示更加直观&#xff0c;可以清晰看到最近的网站数据&#xff0c;特别是对于老板&#xff0…

WebSocket连接状态监控与自动重连实现

WebSocket连接状态监控与自动重连实现 下面我将实现一个具有连接状态监控和自动重连功能的WebSocket聊天室界面。 设计思路 创建直观的连接状态指示器实现自动重连机制&#xff0c;包括&#xff1a; 指数退避策略&#xff08;重连间隔逐渐增加&#xff09;最大重连次数限制手动…

【Vue2手录05】响应式原理与双向绑定 v-model

一、Vue2响应式原理&#xff08;底层基础&#xff09; Vue2的“响应式”核心是数据变化自动触发视图更新&#xff0c;其实现依赖Object.defineProperty API&#xff0c;但受JavaScript语言机制限制&#xff0c;存在“数组/对象修改盲区”&#xff0c;这是理解后续内容的关键。 …

探索大语言模型(LLM):Ollama快速安装部署及使用(含Linux环境下离线安装)

前言 Ollama 是一个开源的本地化大模型运行平台&#xff0c;支持用户直接在个人计算机上部署、管理和交互大型语言模型&#xff08;LLMs&#xff09;&#xff0c;无需依赖云端服务。而且其混合推理的特性也使得CPU和GPU的算力能够充分被使用&#xff0c;能够在同等配置下跑更大…

渗透测试信息收集详解

我们来详细解析一下渗透测试中信息收集&#xff08;Information Gathering&#xff09;的完整内容、步骤及工具方法。信息收集是整个渗透测试的基石&#xff0c;其深度和广度直接决定了后续测试的成功率&#xff0c;因此有“渗透测试成功与否&#xff0c;90%取决于信息收集”的…

Kafka面试精讲 Day 16:生产者性能优化策略

【Kafka面试精讲 Day 16】生产者性能优化策略 在“Kafka面试精讲”系列的第16天&#xff0c;我们将聚焦于生产者性能优化策略。这是Kafka中极为关键的技术点&#xff0c;也是大厂面试中的高频考点——尤其是在涉及高并发数据写入、日志采集、实时数仓等场景时&#xff0c;面试…

深入解析AI温度参数:控制文本生成的随机性与创造性

引言 在人工智能飞速发展的今天&#xff0c;文本生成模型如GPT系列已经成为内容创作、代码编写、对话系统等领域的核心工具。然而&#xff0c;许多用户在使用这些模型时&#xff0c;可能会发现输出结果有时过于保守和重复&#xff0c;有时又过于天马行空而缺乏连贯性。这背后其…

20250912在荣品RD-RK3588-MID开发板的Android13系统下在接电脑的时候禁止充电

20250912在荣品RD-RK3588-MID开发板的Android13系统下在接电脑的时候禁止充电 2025/9/12 10:21缘起&#xff1a;某人的电脑接荣品RD-RK3588-MID开发板的时候做APK开发板的时候&#xff0c;通过Android Studio连接荣品RD-RK3588-MID开发板。 经常断联/时断时续。投诉了/抱怨了好…

Unity Addressable System 本地服务器功能验证

1.从Package Manger里安装Addressable 注意这里有Addressables和Addressables两个包&#xff0c;前者是核心框架&#xff0c;处理跨平台通用逻辑&#xff0c;比如用 地址&#xff08;Address&#xff09;来异步加载、卸载资源&#xff1b;自动做引用计数&#xff0c;避免资源泄…

碎片化采购是座金矿:数字化正重构电子元器件分销的价值链

在电子元器件的分销江湖里&#xff0c;长期存在着一条隐秘的“鄙视链”&#xff1a;订单金额大、需求稳定的头部客户是众星捧月的“香饽饽”&#xff0c;而需求碎片化、品类繁多的小微企业长尾订单&#xff0c;则常被视作食之无味、弃之可惜的“鸡肋”。行业固有认知告诉我们&a…

Typescript - 通俗易懂的 interface 接口,创建接口 / 基础使用 / 可选属性 / 只读属性 / 任意属性(详细教程)

前言 在面向对象语言中&#xff0c;接口是一个很重要的概念&#xff0c;它是对行为的抽象&#xff0c;而具体如何行动需要由类去实现。 TypeScript 中的接口是一个非常灵活的概念&#xff0c;除了可用于 对类的一部分行为进行抽象 以外&#xff0c;也常用于对「对象的形状&…

【硬件-笔试面试题-92】硬件/电子工程师,笔试面试题(知识点:米勒效应,米勒平台)

题目汇总版--链接&#xff1a; 【硬件-笔试面试题】硬件/电子工程师&#xff0c;笔试面试题汇总版&#xff0c;持续更新学习&#xff0c;加油&#xff01;&#xff01;&#xff01;-CSDN博客 【硬件-笔试面试题-92】硬件/电子工程师&#xff0c;笔试面试题&#xff08;知识点…

C语言深度入门系列:第十一篇 - 动态内存管理与数据结构:程序世界的高效算法大师

C语言深度入门系列&#xff1a;第十一篇 - 动态内存管理与数据结构&#xff1a;程序世界的高效算法大师 本章目标 本章将深入探讨C语言中的动态内存管理和经典数据结构实现&#xff0c;这是从基础编程迈向算法工程师的关键一步。您将掌握内存的精确控制、理解各种数据结构的本质…

Go 语言开发环境安装与 GOPROXY 镜像配置(含依赖管理与版本切换技巧)

在国内搭建 Go 开发环境的最大障碍不是“怎么装”&#xff0c;而是“下不动”。本文是我在多台 Windows / macOS / Linux 机器上踩坑后的整合笔记&#xff1a;用最稳妥的安装方式 合理的镜像配置 一套通吃的依赖/版本管理流程&#xff0c;把速度、稳定性和可维护性一次性解决…

崔传波教授:以科技与人文之光,点亮近视患者的清晰视界‌

崔传波教授&#xff1a;以科技与人文之光&#xff0c;点亮近视患者的清晰视界‌在临沂新益民眼科医院&#xff0c;有这样一位眼科医师——他不仅是近视矫正领域的专家&#xff0c;更是“金视青春之光手术”的研发倡导者。‌崔传波教授‌以其深厚的学术功底、创新的技术理念和以…

如何写过滤条件wrapper的使用

模糊查询 &#xff1a;功能是&#xff1a;查询 WORK_NUM 字段包含 ${workOrder.workNum} 的记录。<if test"workOrder.workNum ! null and workOrder.workNum ! ">and b.WORK_NUM like CONCAT(%,CONCAT(#{workOrder.workNum},%)) </if>一、比较条件方法示…

【Spring Boot 报错已解决】彻底解决 “Main method not found in class com.xxx.Application” 报错

文章目录引言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路二、解决方法2.1 方法一&#xff1a;添加标准的main方法2.2 方法二&#xff1a;检查main方法的定义是否规范2.3 方法三&#xff1a;检查主类的位置是否正确2.4 方法四&#xff1a;重新构建项目并清理缓存三、其他…