manimgeo.components.base.base_geometry 源代码

from __future__ import annotations

from pydantic import Field, ValidationError
from .base_pydantic import BaseModelN
from typing import List, Optional, Any, Generic, Hashable

from .base_adapter import GeometryAdapter

# 日志
import logging
logger = logging.getLogger(__name__)

from .base_argsmodel import _ArgsModelT

[文档] class BaseGeometry(BaseModelN, Generic[_ArgsModelT]): """几何对象基类""" name: str = Field(description="几何对象名称") attrs: List[str] = Field(default_factory=list, description="几何对象属性列表", init=False) adapter: GeometryAdapter[Any] = Field(description="几何对象参数适配器", init=False) dependencies: List[BaseGeometry] = Field(default_factory=list, description="当前几何对象直接依赖的其他几何对象列表", init=False) dependents: List[BaseGeometry] = Field(default_factory=list, description="依赖于当前几何对象的其他几何对象列表", init=False) on_error: bool = Field(default=False, description="是否在更新过程中发生错误", init=False) def __repr__(self): # 原始 BaseModelN 的 __repr__ 方法开销巨大,改为简化输出 return f"{self.__class__.__name__}(name={self.name}, adapter={self.adapter}, attrs={self.attrs}, dependencies={len(self.dependencies)}, dependents={len(self.dependents)}, on_error={self.on_error})" def __hash__(self): """ 每个几何对象实例都具有唯一的哈希值,即其内容相同 """ return hash(id(self)) def __eq__(self, other): """ 比较两个几何对象是否为同一个实例。 """ if not isinstance(other, BaseGeometry): return NotImplemented return id(self) == id(other)
[文档] def get_name(self, default_name: str): """以统一方式设置几何对象名称""" if default_name != "": return default_name else: return f"{type(self).__name__}[{self.adapter.construct_type}]@{id(self) % 100000}"
[文档] def add_dependent(self, obj: BaseGeometry): """ 添加依赖于当前对象的下游对象 - `obj`: 下游依赖对象 """ if obj not in self.dependents: self.dependents.append(obj)
[文档] def remove_dependent(self, obj: Optional[BaseGeometry]): """ 移除依赖于当前对象的下游对象 - `obj`: 需要移除的下游依赖对象,如果为 None 则移除所有依赖 """ if obj is None: self.dependents.clear() else: if obj in self.dependents: self.dependents.remove(obj)
def _add_dependency(self, obj: BaseGeometry): """ 添加当前对象直接依赖的上游几何对象 - `obj`: 上游依赖对象 """ if obj not in self.dependencies: self.dependencies.append(obj) obj.add_dependent(self) # 同时将当前对象添加到上游的 dependents 列表中 def _remove_dependency(self, obj: Optional[BaseGeometry]): """ 移除当前对象直接依赖的上游几何对象 - `obj`: 需要移除的上游依赖对象,如果为 None 则移除所有依赖 """ if obj is None: for dep in self.dependencies: dep.remove_dependent(self) self.dependencies.clear() else: if obj in self.dependencies: self.dependencies.remove(obj) obj.remove_dependent(self)
[文档] def board_update_msg(self, on_error: bool = False): """ 向所有下游依赖项发出更新信号 - `on_error`: 是否在更新过程中发生错误,默认为 False """ for dep in self.dependents: dep.update() # 递归更新下游 dep.on_error = on_error
def _extract_dependencies_from_args(self, args_model: _ArgsModelT): """ 从 Pydantic 参数模型中提取依赖的几何对象,并添加到当前对象的依赖列表中 - `args_model`: Pydantic 参数模型实例 """ # 调用 ArgsModelBase 的 _get_deps 方法获取依赖几何对象列表 deps = args_model._get_deps() # 添加到当前的依赖列表中 for dep in deps: if isinstance(dep, BaseGeometry): self._add_dependency(dep) else: logger.warning(f"参数模型 {args_model.__class__.__name__} 中包含非几何对象依赖: {dep},将被忽略")
[文档] def update(self, new_args_model: Optional[_ArgsModelT] = None): """ 执行当前对象的更新 - `new_args_model`: 如果需要更新构造参数,则传入新的 Pydantic 参数模型实例。如果传入,会尝试替换 adapter.args 注意不能更改参数模型的类型,只能更改参数模型的实例 """ if new_args_model: try: # 检查传入的模型类型是否与当前适配器期望的 args 类型兼容 # 简化的检查,更严格的检查可能需要比较 TypeVar ArgsModel if not isinstance(new_args_model, type(self.adapter.args)): raise TypeError(f"传入的参数模型类型 {type(new_args_model).__name__} 与当前适配器期望的类型 {type(self.adapter.args).__name__} 不匹配。") self.adapter.args = new_args_model except (TypeError, ValidationError) as e: logger.error(f"更新对象 {self.name} 的参数失败: {e}") self.board_update_msg(True) self.on_error = True return except Exception as e: logger.error(f"更新对象 {self.name} 的参数时发生未知错误: {e}") self.board_update_msg(True) self.on_error = True return try: # 调用适配器进行计算 self.adapter() # 将参数从适配器绑定到几何对象 self.adapter.bind_attributes(self, self.attrs) except Exception as e: logger.warning(f"节点 {self.name} ({type(self).__name__}) 计算失败", exc_info=True) # 传播更新消息并标记错误 self.board_update_msg(True) self.on_error = True raise e # 成功更新,清除错误标记 self.on_error = False # 向下游广播更新信息 self.board_update_msg()