15 KiB
15 KiB
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
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:
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:
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.5v(float, optional): V parameter, default 0.5
Returns:
simplecadapi.core.Vec3: Normal vector
Raises:
ValueError: When normal vector retrieval fails
Example:
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:
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
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
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
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
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
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
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]