Skip to content

Commit

Permalink
refactor and rename designer.py to pipeline.py
Browse files Browse the repository at this point in the history
This implements the previous designer class a render pipeline between
the frontend and the output backend.
Clipping and linetype rendering will be separated into
independent stages in the future.
  • Loading branch information
mozman committed Mar 24, 2024
1 parent 6df4df3 commit 60fed54
Show file tree
Hide file tree
Showing 2 changed files with 307 additions and 196 deletions.
88 changes: 44 additions & 44 deletions src/ezdxf/addons/drawing/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
from .type_hints import Color

if TYPE_CHECKING:
from .designer import Designer
from .pipeline import AbstractPipeline

__all__ = ["Frontend", "UniversalFrontend"]

Expand Down Expand Up @@ -126,18 +126,18 @@ class UniversalFrontend:
def __init__(
self,
ctx: RenderContext,
designer: Designer,
pipeline: AbstractPipeline,
config: Configuration = Configuration(),
bbox_cache: Optional[ezdxf.bbox.Cache] = None,
):
# RenderContext contains all information to resolve resources for a
# specific DXF document.
self.ctx = ctx
# the designer is the connection between frontend and backend
self.designer = designer
designer.set_draw_entities_callback(self.draw_entities_callback)
self.pipeline = pipeline
pipeline.set_draw_entities_callback(self.draw_entities_callback)
self.config = ctx.update_configuration(config)
designer.set_config(self.config)
pipeline.set_config(self.config)

if self.config.pdsize is None or self.config.pdsize <= 0:
self.log_message("relative point size is not supported")
Expand Down Expand Up @@ -171,7 +171,7 @@ def __init__(

@property
def text_engine(self):
return self.designer.text_engine
return self.pipeline.text_engine

def _build_dispatch_table(self) -> TDispatchTable:
dispatch_table: TDispatchTable = {
Expand Down Expand Up @@ -302,7 +302,7 @@ def draw_layout(
filter_func=filter_func,
)
if finalize:
self.designer.finalize()
self.pipeline.finalize()

def set_background(self, color: Color) -> None:
policy = self.config.background_policy
Expand All @@ -323,7 +323,7 @@ def set_background(self, color: Color) -> None:
color = self.config.custom_bg_color
if override:
self.ctx.current_layout_properties.set_colors(color)
self.designer.set_background(color)
self.pipeline.set_background(color)

def draw_entities(
self,
Expand All @@ -350,10 +350,10 @@ def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None:
properties: resolved entity properties
"""
self.designer.enter_entity(entity, properties)
self.pipeline.enter_entity(entity, properties)
if not entity.is_virtual:
# top level entity
self.designer.set_current_entity_handle(entity.dxf.handle)
self.pipeline.set_current_entity_handle(entity.dxf.handle)
if (
entity.proxy_graphic
and self.config.proxy_graphic_policy == ProxyGraphicPolicy.PREFER
Expand Down Expand Up @@ -384,22 +384,22 @@ def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None:
else:
self.skip_entity(entity, "unsupported")

self.designer.exit_entity(entity)
self.pipeline.exit_entity(entity)

def draw_line_entity(self, entity: DXFGraphic, properties: Properties) -> None:
d, dxftype = entity.dxf, entity.dxftype()
if dxftype == "LINE":
self.designer.draw_line(d.start, d.end, properties)
self.pipeline.draw_line(d.start, d.end, properties)

elif dxftype in ("XLINE", "RAY"):
start = d.start
delta = d.unit_vector * self.config.infinite_line_length
if dxftype == "XLINE":
self.designer.draw_line(
self.pipeline.draw_line(
start - delta / 2, start + delta / 2, properties
)
elif dxftype == "RAY":
self.designer.draw_line(start, start + delta, properties)
self.pipeline.draw_line(start, start + delta, properties)
else:
raise TypeError(dxftype)

Expand All @@ -417,15 +417,15 @@ def draw_text_entity(self, entity: DXFGraphic, properties: Properties) -> None:
def get_font_face(self, properties: Properties) -> fonts.FontFace:
font_face = properties.font
if font_face is None:
return self.designer.default_font_face
return self.pipeline.default_font_face
return font_face

def draw_text_entity_2d(self, entity: DXFGraphic, properties: Properties) -> None:
if isinstance(entity, Text):
for line, transform, cap_height in simplified_text_chunks(
entity, self.text_engine, font_face=self.get_font_face(properties)
):
self.designer.draw_text(
self.pipeline.draw_text(
line, transform, properties, cap_height, entity.dxftype()
)
else:
Expand Down Expand Up @@ -454,20 +454,20 @@ def draw_simple_mtext(self, mtext: MText, properties: Properties) -> None:
for line, transform, cap_height in simplified_text_chunks(
mtext, self.text_engine, font_face=self.get_font_face(properties)
):
self.designer.draw_text(
self.pipeline.draw_text(
line, transform, properties, cap_height, mtext.dxftype()
)

def draw_complex_mtext(self, mtext: MText, properties: Properties) -> None:
"""Draw the content of a MTEXT entity including inline formatting codes."""
complex_mtext_renderer(self.ctx, self.designer, mtext, properties)
complex_mtext_renderer(self.ctx, self.pipeline, mtext, properties)

def draw_curve_entity(self, entity: DXFGraphic, properties: Properties) -> None:
try:
path = make_path(entity)
except AttributeError: # API usage error
raise TypeError(f"Unsupported DXF type {entity.dxftype()}")
self.designer.draw_path(path, properties)
self.pipeline.draw_path(path, properties)

def draw_point_entity(self, entity: DXFGraphic, properties: Properties) -> None:
point = cast(Point, entity)
Expand All @@ -484,17 +484,17 @@ def draw_point_entity(self, entity: DXFGraphic, properties: Properties) -> None:
pdmode = 0

if pdmode == 0:
self.designer.draw_point(entity.dxf.location, properties)
self.pipeline.draw_point(entity.dxf.location, properties)
else:
for entity in point.virtual_entities(pdsize, pdmode):
dxftype = entity.dxftype()
if dxftype == "LINE":
start = entity.dxf.start
end = entity.dxf.end
if start.isclose(end):
self.designer.draw_point(start, properties)
self.pipeline.draw_point(start, properties)
else: # direct draw by backend is OK!
self.designer.draw_line(start, end, properties)
self.pipeline.draw_line(start, end, properties)
pass
elif dxftype == "CIRCLE":
self.draw_curve_entity(entity, properties)
Expand All @@ -517,16 +517,16 @@ def draw_solid_entity(self, entity: DXFGraphic, properties: Properties) -> None:
return
edge_visibility = entity.get_edges_visibility()
if all(edge_visibility):
self.designer.draw_path(from_vertices(points), properties)
self.pipeline.draw_path(from_vertices(points), properties)
else:
for a, b, visible in zip(points, points[1:], edge_visibility):
if visible:
self.designer.draw_line(a, b, properties)
self.pipeline.draw_line(a, b, properties)

elif isinstance(entity, Solid):
# set solid fill type for SOLID and TRACE
properties.filling = Filling()
self.designer.draw_filled_polygon(
self.pipeline.draw_filled_polygon(
entity.wcs_vertices(close=False), properties
)
else:
Expand Down Expand Up @@ -566,7 +566,7 @@ def timeout() -> bool:
(e.x, e.y, elevation)
)
lines.append((s, e))
self.designer.draw_solid_lines(lines, properties)
self.pipeline.draw_solid_lines(lines, properties)

def draw_hatch_entity(
self,
Expand Down Expand Up @@ -616,10 +616,10 @@ def draw_hatch_entity(
paths = closed_loops(boundary_paths, ocs, elevation)
if show_only_outline:
for p in ignore_text_boxes(paths):
self.designer.draw_path(p, properties)
self.pipeline.draw_path(p, properties)
return
if paths:
self.designer.draw_filled_paths(ignore_text_boxes(paths), properties)
self.pipeline.draw_filled_paths(ignore_text_boxes(paths), properties)

def draw_mpolygon_entity(self, entity: DXFGraphic, properties: Properties):
def resolve_fill_color() -> str:
Expand Down Expand Up @@ -654,14 +654,14 @@ def resolve_fill_color() -> str:
properties.color = line_color
# draw boundary paths as lines
for loop in loops:
self.designer.draw_path(loop, properties)
self.pipeline.draw_path(loop, properties)

def draw_wipeout_entity(self, entity: DXFGraphic, properties: Properties) -> None:
wipeout = cast(Wipeout, entity)
properties.filling = Filling()
properties.color = self.ctx.current_layout_properties.background_color
clipping_polygon = wipeout.boundary_path_wcs()
self.designer.draw_filled_polygon(clipping_polygon, properties)
self.pipeline.draw_filled_polygon(clipping_polygon, properties)

def draw_viewport(self, vp: Viewport) -> None:
# the "active" viewport and invisible viewports should be filtered at this
Expand All @@ -672,7 +672,7 @@ def draw_viewport(self, vp: Viewport) -> None:
if not vp.is_top_view:
self.log_message("Cannot render non top-view viewports")
return
self.designer.draw_viewport(vp, self.ctx, self._bbox_cache)
self.pipeline.draw_viewport(vp, self.ctx, self._bbox_cache)

def draw_ole2frame_entity(self, entity: DXFGraphic, properties: Properties) -> None:
ole2frame = cast(OLE2Frame, entity)
Expand Down Expand Up @@ -756,12 +756,12 @@ def draw_image_entity(self, entity: DXFGraphic, properties: Properties) -> None:
use_clipping_boundary=image.dxf.flags & Image.USE_CLIPPING_BOUNDARY,
remove_outside=image.dxf.clip_mode == 0,
)
self.designer.draw_image(image_data, properties)
self.pipeline.draw_image(image_data, properties)

elif show_filename_if_missing:
default_cap_height = 20
text = image_def.dxf.filename
font = self.designer.text_engine.get_font(
font = self.pipeline.text_engine.get_font(
self.get_font_face(properties)
)
text_width = font.text_width_ex(text, default_cap_height)
Expand All @@ -776,15 +776,15 @@ def draw_image_entity(self, entity: DXFGraphic, properties: Properties) -> None:
transform = (
Matrix44.scale(scale) @ translate @ image.get_wcs_transform()
)
self.designer.draw_text(
self.pipeline.draw_text(
text,
transform,
properties,
default_cap_height,
)

points = [v.vec2 for v in image.boundary_path_wcs()]
self.designer.draw_solid_lines(list(zip(points, points[1:])), properties)
self.pipeline.draw_solid_lines(list(zip(points, points[1:])), properties)

elif self.config.image_policy == ImagePolicy.PROXY:
self.draw_proxy_graphic(entity.proxy_graphic, entity.doc)
Expand All @@ -804,7 +804,7 @@ def _draw_filled_rect(
props.color = color
# default SOLID filling
props.filling = Filling()
self.designer.draw_filled_polygon(points, props)
self.pipeline.draw_filled_polygon(points, props)

def draw_mesh_entity(self, entity: DXFGraphic, properties: Properties) -> None:
builder = MeshBuilder.from_mesh(entity) # type: ignore
Expand All @@ -814,7 +814,7 @@ def draw_mesh_builder_entity(
self, builder: MeshBuilder, properties: Properties
) -> None:
for face in builder.faces_as_vertices():
self.designer.draw_path(
self.pipeline.draw_path(
from_vertices(face, close=True), properties=properties
)

Expand Down Expand Up @@ -855,10 +855,10 @@ def draw_polyline_entity(self, entity: DXFGraphic, properties: Properties) -> No
points = polygon # type: ignore
# Set default SOLID filling for LWPOLYLINE
properties.filling = Filling()
self.designer.draw_filled_polygon(points, properties)
self.pipeline.draw_filled_polygon(points, properties)
return

self.designer.draw_path(make_path(entity), properties)
self.pipeline.draw_path(make_path(entity), properties)

def draw_composite_entity(self, entity: DXFGraphic, properties: Properties) -> None:
def draw_insert(insert: Insert):
Expand All @@ -878,7 +878,7 @@ def draw_insert(insert: Insert):
boundary_path.inner_polygon(),
outer_bounds=boundary_path.outer_bounds(),
)
self.designer.push_clipping_shape(clipping_shape, None)
self.pipeline.push_clipping_shape(clipping_shape, None)

# draw_entities() includes the visibility check:
self.draw_entities(
Expand All @@ -889,11 +889,11 @@ def draw_insert(insert: Insert):
)

if is_clipping_active and clip.get_xclip_frame_policy():
self.designer.draw_path(
self.pipeline.draw_path(
path=from_vertices(boundary_path.inner_polygon(), close=True),
properties=properties,
)
self.designer.pop_clipping_shape()
self.pipeline.pop_clipping_shape()

if isinstance(entity, Insert):
self.ctx.push_state(properties)
Expand Down Expand Up @@ -949,9 +949,9 @@ def __init__(
config: Configuration = Configuration(),
bbox_cache: Optional[ezdxf.bbox.Cache] = None,
):
from .designer import Designer2d
from .pipeline import RenderPipeline2d

super().__init__(ctx, Designer2d(out), config, bbox_cache)
super().__init__(ctx, RenderPipeline2d(out), config, bbox_cache)


def is_spatial_text(extrusion: Vec3) -> bool:
Expand Down
Loading

0 comments on commit 60fed54

Please sign in to comment.