Files
cadSet/SimpleCADAPI/docs/core/face.md
T
2026-07-22 19:38:36 +08:00

546 lines
15 KiB
Markdown

# Face
## Overview
`Face` is the face class in the SimpleCAD API, representing 2D surface geometry. A face is bounded by one or more wires, including an outer boundary and possibly inner boundaries (holes). It wraps the OCP Face object and adds tagging functionality.
## Class Definition
```python
class Face(TaggedMixin):
"""面类,包装OCP的Face,添加标签功能"""
```
## Inheritance
- Inherits from `TaggedMixin`, providing tag and metadata functionality
## Usage
- Represent 2D surface areas
- Form the boundary of solids (Solid)
- Define cross-sections for sweep, extrude, and other operations
- Calculate geometric properties such as area and normal vectors
## Constructor
### `__init__(wrapped)`
Initializes a face object.
**Parameters:**
- `wrapped` (OCP TopoDS_Face): A OCP face object
**Raises:**
- `ValueError`: When the input face object is invalid
**Example:**
```python
from simplecadapi import (
make_rectangle_rface,
make_circle_rface,
make_face_from_wire_rface,
make_rectangle_rwire
)
# 通过 SimpleCAD 函数创建面
rectangle = make_rectangle_rface(width=5, height=3)
circle = make_circle_rface(center=(0, 0, 0), radius=2.0)
# 从线创建面
wire = make_rectangle_rwire(width=4, height=4)
face_from_wire = make_face_from_wire_rface(wire)
```
## Main Properties
- `wrapped`: The underlying OCP face object
- `_tags`: Tag set (inherited from TaggedMixin)
- `_metadata`: Metadata dictionary (inherited from TaggedMixin)
## Common Methods
### `get_area()`
Get the area of the face.
**Returns:**
- `float`: The area of the face
**Raises:**
- `ValueError`: When area retrieval fails
**Example:**
```python
from simplecadapi import make_rectangle_rface, make_circle_rface
import math
# 矩形面
rectangle = make_rectangle_rface(width=5, height=3)
rect_area = rectangle.get_area()
print(f"矩形面积: {rect_area}") # 15.0
# 圆形面
circle = make_circle_rface(center=(0, 0, 0), radius=2.0)
circle_area = circle.get_area()
expected_area = math.pi * 2.0 * 2.0
print(f"圆形面积: {circle_area:.3f}, 期望: {expected_area:.3f}")
```
### `get_normal_at(u, v)`
Get the normal vector of the face at the specified parameter position.
**Parameters:**
- `u` (float, optional): U parameter, default 0.5
- `v` (float, optional): V parameter, default 0.5
**Returns:**
- `simplecadapi.core.Vec3`: Normal vector
**Raises:**
- `ValueError`: When normal vector retrieval fails
**Example:**
```python
from simplecadapi import make_rectangle_rface
rectangle = make_rectangle_rface(width=5, height=3)
normal = rectangle.get_normal_at()
print(f"法向量: ({normal.x:.3f}, {normal.y:.3f}, {normal.z:.3f})")
```
### `get_outer_wire()`
Get the outer boundary wire of the face.
**Returns:**
- `Wire`: Outer boundary wire object
**Raises:**
- `ValueError`: When outer boundary wire retrieval fails
**Example:**
```python
from simplecadapi import make_rectangle_rface
rectangle = make_rectangle_rface(width=5, height=3)
outer_wire = rectangle.get_outer_wire()
edges = outer_wire.get_edges()
print(f"外边界由 {len(edges)} 条边组成")
```
### Tagging and Metadata
Use the functional public API `apply_tag(shape, tag)` and `list_tags(shape)` for tags. Use `set_metadata(key, value)` and `get_metadata(key, default=None)` for structured metadata.
## Usage Examples
### Creating Different Types of Faces
```python
from simplecadapi import (
make_rectangle_rface,
make_circle_rface,
make_face_from_wire_rface,
make_polyline_rwire
)
# 矩形面
rectangle = make_rectangle_rface(width=10, height=6)
apply_tag(rectangle, "rectangle")
apply_tag(rectangle, "quadrilateral")
# 圆形面
circle = make_circle_rface(center=(0, 0, 0), radius=3.0)
apply_tag(circle, "circle")
apply_tag(circle, "curved")
# 复杂多边形面
points = [
(0, 0, 0), (4, 0, 0), (4, 3, 0), (2, 5, 0), (0, 3, 0), (0, 0, 0)
]
polygon_wire = make_polyline_rwire(points=points)
polygon = make_face_from_wire_rface(polygon_wire)
apply_tag(polygon, "polygon")
apply_tag(polygon, "complex")
# 分析面的属性
faces = [rectangle, circle, polygon]
for face in faces:
area = face.get_area()
normal = face.get_normal_at()
outer_wire = face.get_outer_wire()
edges = outer_wire.get_edges()
tags = list_tags(face)
print(f"面类型: {tags}")
print(f" 面积: {area:.3f}")
print(f" 法向量: ({normal.x:.3f}, {normal.y:.3f}, {normal.z:.3f})")
print(f" 边数: {len(edges)}")
print()
```
### Geometric Analysis of Faces
```python
from simplecadapi import make_rectangle_rface, make_circle_rface
import math
def analyze_face_geometry():
"""分析面的几何属性"""
# 创建不同尺寸的矩形
rectangles = [
make_rectangle_rface(width=2, height=3),
make_rectangle_rface(width=4, height=4),
make_rectangle_rface(width=6, height=2)
]
# 创建不同半径的圆
circles = [
make_circle_rface(center=(0, 0, 0), radius=1.0),
make_circle_rface(center=(0, 0, 0), radius=2.0),
make_circle_rface(center=(0, 0, 0), radius=3.0)
]
# 分析矩形
for i, rect in enumerate(rectangles):
area = rect.get_area()
outer_wire = rect.get_outer_wire()
edges = outer_wire.get_edges()
# 计算周长
perimeter = sum(edge.get_length() for edge in edges)
# 计算长宽比
lengths = [edge.get_length() for edge in edges]
lengths.sort()
aspect_ratio = lengths[1] / lengths[0] if lengths[0] > 0 else 1.0
apply_tag(rect, f"rectangle_{i}")
rect.set_metadata("area", area)
rect.set_metadata("perimeter", perimeter)
rect.set_metadata("aspect_ratio", aspect_ratio)
if aspect_ratio == 1.0:
apply_tag(rect, "square")
elif aspect_ratio > 2.0:
apply_tag(rect, "elongated")
print(f"矩形 {i}: 面积={area:.3f}, 周长={perimeter:.3f}, 长宽比={aspect_ratio:.3f}")
# 分析圆形
for i, circle in enumerate(circles):
area = circle.get_area()
outer_wire = circle.get_outer_wire()
edges = outer_wire.get_edges()
# 计算周长(圆周长)
perimeter = sum(edge.get_length() for edge in edges)
# 从面积计算半径
radius_from_area = math.sqrt(area / math.pi)
# 从周长计算半径
radius_from_perimeter = perimeter / (2 * math.pi)
apply_tag(circle, f"circle_{i}")
circle.set_metadata("area", area)
circle.set_metadata("perimeter", perimeter)
circle.set_metadata("radius_from_area", radius_from_area)
circle.set_metadata("radius_from_perimeter", radius_from_perimeter)
if radius_from_area < 1.5:
apply_tag(circle, "small")
elif radius_from_area > 2.5:
apply_tag(circle, "large")
else:
apply_tag(circle, "medium")
print(f"圆形 {i}: 面积={area:.3f}, 周长={perimeter:.3f}, 半径={radius_from_area:.3f}")
analyze_face_geometry()
```
### Faces with Holes
```python
from simplecadapi import (
make_rectangle_rface,
make_circle_rface,
make_face_from_wire_rface,
make_rectangle_rwire,
make_circle_rwire
)
def create_face_with_holes():
"""创建带孔的面(概念示例)"""
# 创建外边界
outer_boundary = make_rectangle_rwire(width=10, height=8)
# 创建内边界(孔)
hole1 = make_circle_rwire(center=(3, 2, 0), radius=1.0)
hole2 = make_circle_rwire(center=(7, 6, 0), radius=1.5)
# 注意:SimpleCAD 当前版本可能不直接支持多边界面
# 这里展示概念和标签使用
# 主面
main_face = make_rectangle_rface(width=10, height=8)
apply_tag(main_face, "main_surface")
apply_tag(main_face, "with_holes")
# 孔面(用于布尔运算)
hole_face1 = make_circle_rface(center=(3, 2, 0), radius=1.0)
apply_tag(hole_face1, "hole")
apply_tag(hole_face1, "circular")
hole_face1.set_metadata("hole_id", 1)
hole_face1.set_metadata("center", (3, 2, 0))
hole_face1.set_metadata("radius", 1.0)
hole_face2 = make_circle_rface(center=(7, 6, 0), radius=1.5)
apply_tag(hole_face2, "hole")
apply_tag(hole_face2, "circular")
hole_face2.set_metadata("hole_id", 2)
hole_face2.set_metadata("center", (7, 6, 0))
hole_face2.set_metadata("radius", 1.5)
# 计算有效面积
main_area = main_face.get_area()
hole1_area = hole_face1.get_area()
hole2_area = hole_face2.get_area()
effective_area = main_area - hole1_area - hole2_area
main_face.set_metadata("total_area", main_area)
main_face.set_metadata("hole_area", hole1_area + hole2_area)
main_face.set_metadata("effective_area", effective_area)
print(f"主面面积: {main_area:.3f}")
print(f"孔面积总和: {hole1_area + hole2_area:.3f}")
print(f"有效面积: {effective_area:.3f}")
return main_face, [hole_face1, hole_face2]
main_face, holes = create_face_with_holes()
```
### Face Transformation and Operations
```python
from simplecadapi import (
make_rectangle_rface,
translate_shape,
rotate_shape
)
def transform_faces():
"""变换面的操作"""
# 创建基础面
base_face = make_rectangle_rface(width=4, height=3)
apply_tag(base_face, "base")
apply_tag(base_face, "original")
# 应用变换
translated_face = translate_shape(base_face, offset=(6, 0, 0))
apply_tag(translated_face, "translated")
rotated_face = rotate_shape(base_face, axis=(0, 0, 1), angle=45)
apply_tag(rotated_face, "rotated")
elevated_face = translate_shape(base_face, offset=(0, 0, 2))
apply_tag(elevated_face, "elevated")
# 收集所有面
all_faces = [base_face, translated_face, rotated_face, elevated_face]
# 分析变换结果
for face in all_faces:
area = face.get_area()
normal = face.get_normal_at()
outer_wire = face.get_outer_wire()
edges = outer_wire.get_edges()
# 计算边界框
all_coords = []
for edge in edges:
start_coords = edge.get_start_vertex().get_coordinates()
end_coords = edge.get_end_vertex().get_coordinates()
all_coords.extend([start_coords, end_coords])
if all_coords:
min_x = min(coord[0] for coord in all_coords)
max_x = max(coord[0] for coord in all_coords)
min_y = min(coord[1] for coord in all_coords)
max_y = max(coord[1] for coord in all_coords)
min_z = min(coord[2] for coord in all_coords)
max_z = max(coord[2] for coord in all_coords)
face.set_metadata("bbox_min", (min_x, min_y, min_z))
face.set_metadata("bbox_max", (max_x, max_y, max_z))
face.set_metadata("area", area)
face.set_metadata("normal", (normal.x, normal.y, normal.z))
print(f"面标签: {list_tags(face)}")
print(f" 面积: {area:.3f}")
print(f" 法向量: ({normal.x:.3f}, {normal.y:.3f}, {normal.z:.3f})")
if face.get_metadata("bbox_min"):
print(f" 边界框: {face.get_metadata('bbox_min')}{face.get_metadata('bbox_max')}")
print()
transform_faces()
```
### Face Classification and Filtering
```python
from simplecadapi import make_rectangle_rface, make_circle_rface
def classify_faces():
"""分类和筛选面"""
# 创建不同类型的面
faces = []
# 小矩形
small_rects = [
make_rectangle_rface(width=1, height=1),
make_rectangle_rface(width=2, height=1),
make_rectangle_rface(width=1, height=2)
]
# 大矩形
large_rects = [
make_rectangle_rface(width=5, height=4),
make_rectangle_rface(width=6, height=3),
make_rectangle_rface(width=4, height=6)
]
# 圆形
circles = [
make_circle_rface(center=(0, 0, 0), radius=1.0),
make_circle_rface(center=(0, 0, 0), radius=2.0),
make_circle_rface(center=(0, 0, 0), radius=3.0)
]
# 标记面
for i, face in enumerate(small_rects):
apply_tag(face, "rectangle")
apply_tag(face, "small")
face.set_metadata("size_category", "small")
face.set_metadata("shape_type", "rectangle")
faces.append(face)
for i, face in enumerate(large_rects):
apply_tag(face, "rectangle")
apply_tag(face, "large")
face.set_metadata("size_category", "large")
face.set_metadata("shape_type", "rectangle")
faces.append(face)
for i, face in enumerate(circles):
apply_tag(face, "circle")
area = face.get_area()
if area < 10:
apply_tag(face, "small")
face.set_metadata("size_category", "small")
elif area > 20:
apply_tag(face, "large")
face.set_metadata("size_category", "large")
else:
apply_tag(face, "medium")
face.set_metadata("size_category", "medium")
face.set_metadata("shape_type", "circle")
faces.append(face)
# 分类统计
rectangles = [f for f in faces if "rectangle" in list_tags(f)]
circles = [f for f in faces if "circle" in list_tags(f)]
small_faces = [f for f in faces if "small" in list_tags(f)]
large_faces = [f for f in faces if "large" in list_tags(f)]
print(f"总面数: {len(faces)}")
print(f"矩形面: {len(rectangles)}")
print(f"圆形面: {len(circles)}")
print(f"小面: {len(small_faces)}")
print(f"大面: {len(large_faces)}")
# 计算统计信息
total_area = sum(f.get_area() for f in faces)
avg_area = total_area / len(faces)
print(f"总面积: {total_area:.3f}")
print(f"平均面积: {avg_area:.3f}")
return faces
classified_faces = classify_faces()
```
## String Representation
```python
from simplecadapi import make_rectangle_rface
face = make_rectangle_rface(width=5, height=3)
apply_tag(face, "example_face")
face.set_metadata("material", "steel")
print(face)
```
Output:
```
Face:
area: 15.000
normal: [0.000, 0.000, 1.000]
outer_wire:
Wire:
edge_count: 4
closed: True
edges:
edge_0:
length: 5.000
vertices:
start: (0.0, 0.0, 0.0)
end: (5.0, 0.0, 0.0)
edge_1:
length: 3.000
vertices:
start: (5.0, 0.0, 0.0)
end: (5.0, 3.0, 0.0)
edge_2:
length: 5.000
vertices:
start: (5.0, 3.0, 0.0)
end: (0.0, 3.0, 0.0)
edge_3:
length: 3.000
vertices:
start: (0.0, 3.0, 0.0)
end: (0.0, 0.0, 0.0)
tags: [example_face]
metadata:
material: steel
```
## Relationships with Other Geometry
- **Wire (Wire)**: Boundary of the face
- **Edge (Edge)**: Indirectly associated through wires
- **Solid (Solid)**: Faces form the surfaces of a solid
- **Shell (Shell)**: A collection of surfaces composed of multiple faces
## Notes
- Faces must be closed, bounded by closed wires
- The face normal direction follows the right-hand rule
- Area calculation includes all regions bounded by the boundary
- Faces with holes require special treatment (outer boundary + inner boundary)
- Face orientation affects subsequent solid operations
- Complex faces may have self-intersection or degenerate cases
- The u, v parameter range is typically [0, 1]