from __future__ import annotations
from pydantic import Field, model_validator
from typing import TYPE_CHECKING, List, Any, TypeVar, Type
import numpy as np
from ..base import BaseGeometry
from .adapter import LineAdapter
from .args import *
if TYPE_CHECKING:
from ..point import Point
from ..vector import Vector
_LineT = TypeVar('_LineT', bound='Line')
[文档]
class Line(BaseGeometry):
"""
线类
建议对 Line 的子类进行实例化,而不是直接实例化 Line
"""
attrs: List[str] = Field(default=["start", "end", "length", "unit_direction"], description="线对象属性列表", init=False)
start: np.ndarray = Field(default=np.zeros(2), description="线首坐标", init=False)
end: np.ndarray = Field(default=np.zeros(2), description="线尾坐标", init=False)
length: Number = Field(default=0.0, description="线长度", init=False)
unit_direction: np.ndarray = Field(default=np.zeros(2), description="线单位方向向量", init=False)
args: LineConstructArgs = Field(discriminator='construct_type', description="线构造参数")
adapter: LineAdapter = Field(init=False) # adapter 初始化将在 model_post_init 中进行
[文档]
@model_validator(mode='before')
@classmethod
def set_adapter_before_validation(cls, data: Any) -> Any:
"""在验证前设置 adapter 字段"""
if isinstance(data, dict) and 'args' in data:
# 假设 args 已经是 Pydantic 模型或可以被 LineAdapter 接受
data['adapter'] = LineAdapter(args=data['args'])
return data
line_type: Literal["LineSegment", "Ray", "InfinityLine"] = Field(description="线类型,子类会尝试覆盖")
@property
def construct_type(self) -> LineConstructType:
return self.args.construct_type
[文档]
def model_post_init(self, __context: Any):
"""模型初始化后,更新名字并添加依赖关系"""
self.adapter = LineAdapter(args=self.args)
self.name = self.get_name(self.name)
# 添加依赖关系
self._extract_dependencies_from_args(self.args)
self.update() # 首次计算
# 构造方法
[文档]
@classmethod
def TranslationLV(cls: Type[_LineT], line: LineConcrete, vec: Vector, name: str = "") -> _LineT:
"""
平移构造线
- `line`: 原线
- `vec`: 平移向量
"""
return cls(
name=name,
args=TranslationLVArgs(line=line, vector=vec),
) # type: ignore[call-arg]
[文档]
@classmethod
def PP(cls: Type[_LineT], start: Point, end: Point, name: str = "") -> _LineT:
"""
起始点构造线
- `start`: 起点
- `end`: 终点
"""
return cls(
name=name,
args=PPArgs(point1=start, point2=end),
) # type: ignore[call-arg]
[文档]
@classmethod
def PV(cls: Type[_LineT], start: Point, vector: Vector, name: str = "") -> _LineT:
"""
起点方向构造线
- `start`: 起点
- `vector`: 方向向量
"""
return cls(
name=name,
args=PVArgs(start=start, vector=vector),
) # type: ignore[call-arg]
[文档]
@classmethod
def VerticalPL(cls: Type[_LineT], point: Point, line: LineConcrete, name: str = "") -> _LineT:
"""
点与线构造垂直线
- `point`: 垂线经过点
- `line`: 原线
"""
return cls(
name=name,
args=VerticalPLArgs(point=point, line=line),
) # type: ignore[call-arg]
[文档]
@classmethod
def ParallelPL(cls: Type[_LineT], point: Point, line: LineConcrete, distance: Number = 1, name: str = "") -> _LineT:
"""
点与线构造平行线
- `point`: 平行线经过点
- `line`: 原线
- `distance`: 平行线终点与起点的距离,默认为 1
"""
return cls(
name=name,
args=ParallelPLArgs(point=point, line=line, distance=distance),
) # type: ignore[call-arg]
[文档]
class LineSegment(Line):
line_type: Literal["LineSegment"] = "LineSegment"
[文档]
class Ray(Line):
line_type: Literal["Ray"] = "Ray"
[文档]
class InfinityLine(Line):
line_type: Literal["InfinityLine"] = "InfinityLine"