仅栅格化 CAD DXF 文件的选定区域

Rasterising only selected area of a CAD DXF file

给定一个 DXF 文件(2D CAD 绘图),是否可以通过某种方式仅对其一部分进行栅格化?最好在 Python 的 ezdxf 中。就其一部分而言,我指的是选中的矩形区域,而不是单层。

背景:我正在努力在合理的时间内用适当的 DPI 光栅化相当大的 DXF 文件,所以我想也许有一种方法可以通过并行光栅化绘图的不同部分来加快这个过程。我正在使用 ezdxfmatplotlib 后端。

此解决方案以 4 个图块渲染 DXF 文件,包括过滤渲染区域外的 DXF 实体。但是边界框的计算成本也很高,并且重叠区域中的实体会被多次渲染,这意味着此解决方案需要更长的时间作为 single-pass 渲染。但它显示了这个概念。这些图像完美地组合在一起 space 留下来表明这是 4 张图像:

import matplotlib.pyplot as plt
import random

import ezdxf
from ezdxf.addons.drawing import RenderContext, Frontend
from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
from ezdxf import bbox
from ezdxf.math import BoundingBox2d

COLORS = list(range(1, 7))
DPI = 300
WIDTH = 400
HEIGHT = 200
LEFT = 0
BOTTOM = 0

doc = ezdxf.new()
msp = doc.modelspace()


def random_points(count):
    for _ in range(count):
        yield WIDTH * random.random(), HEIGHT * random.random()


for s, e in zip(random_points(100), random_points(100)):
    msp.add_line(s, e, dxfattribs={"color": random.choice(COLORS)})

# detecting the drawing extents by ezdxf can take along time for big files!
cache = bbox.Cache()  # reuse bounding boxes for entity filtering
rect = bbox.extents(msp, cache=cache)
WIDTH = rect.size.x
HEIGHT = rect.size.y
LEFT = rect.extmin.x
BOTTOM = rect.extmin.y


VIEWPORT_X = [LEFT, LEFT + WIDTH / 2, LEFT, LEFT + WIDTH / 2]
VIEWPORT_Y = [BOTTOM, BOTTOM, BOTTOM + HEIGHT / 2, BOTTOM + HEIGHT / 2]

ctx = RenderContext(doc)
for quarter in [0, 1, 2, 3]:
    # setup drawing add-on:
    fig = plt.figure(dpi=300)
    ax = fig.add_axes([0, 0, 1, 1])
    out = MatplotlibBackend(ax)

    # calculate and set render borders:
    left = VIEWPORT_X[quarter]
    bottom = VIEWPORT_Y[quarter]
    ax.set_xlim(left, left + WIDTH / 2)
    ax.set_ylim(bottom, bottom + HEIGHT / 2)

    # set entities outside of the rendering area invisible:
    # Bounding box calculation can be very costly, especially for deep nested
    # block references! If you did the extents calculation and reuse the cache
    # you already have paid the price:
    render_area = BoundingBox2d(
        [(left, bottom), (left + WIDTH / 2, bottom + HEIGHT / 2)])

    for entity in msp:
        entity_bbox = bbox.extents([entity], cache=cache)
        if render_area.intersect(entity_bbox):
            entity.dxf.invisible = 0
        else:
            entity.dxf.invisible = 1

    # finalizing invokes auto-scaling!
    Frontend(ctx, out).draw_layout(msp, finalize=False)

    # set output size in inches
    # width = 6 in x 300 dpi = 1800 px
    # height = 3 in x 300 dpi = 900 px
    fig.set_size_inches(6, 3, forward=True)

    filename = f"lines{quarter}.png"
    print(f'saving to "{filename}"')
    fig.savefig(filename, dpi=300)
    plt.close(fig)

draw_layout() 方法有一个参数 filter_func 来指定接受 DXF 实体作为参数的函数和 returns TrueFalse 来渲染或忽略此实体。这将是在不改变 DXF 内容的情况下过滤渲染区域之外的实体的替代方法。

更新:可以在 github

找到一个改进的例子