395 lines
14 KiB
Python
395 lines
14 KiB
Python
# Copyright (c) 2020-2024, Manfred Moitzi
|
|
# License: MIT License
|
|
from __future__ import annotations
|
|
from typing import TYPE_CHECKING, Optional
|
|
from typing_extensions import Self
|
|
from ezdxf.lldxf import validator
|
|
from ezdxf.lldxf.const import SUBCLASS_MARKER
|
|
from ezdxf.lldxf.attributes import (
|
|
DXFAttr,
|
|
DXFAttributes,
|
|
DefSubclass,
|
|
XType,
|
|
RETURN_DEFAULT,
|
|
group_code_mapping,
|
|
)
|
|
from ezdxf.math import Vec3, Vec2, NULLVEC, X_AXIS, Y_AXIS
|
|
from .dxfentity import base_class, SubclassProcessor, DXFEntity
|
|
from .dxfobj import DXFObject
|
|
from .factory import register_entity
|
|
|
|
if TYPE_CHECKING:
|
|
from ezdxf.lldxf.tagwriter import AbstractTagWriter
|
|
from ezdxf.entities.dxfns import DXFNamespace
|
|
from ezdxf import xref
|
|
|
|
__all__ = ["PlotSettings", "DXFLayout"]
|
|
|
|
acdb_plot_settings = DefSubclass(
|
|
"AcDbPlotSettings",
|
|
{
|
|
# acdb_plot_settings is also part of LAYOUT and LAYOUT has a 'name' attribute
|
|
"page_setup_name": DXFAttr(1, default=""),
|
|
|
|
# An optional empty string selects the default printer/plotter
|
|
"plot_configuration_file": DXFAttr(2, default="", optional=True),
|
|
"paper_size": DXFAttr(4, default="A3"),
|
|
"plot_view_name": DXFAttr(6, default=""),
|
|
"left_margin": DXFAttr(40, default=7.5), # in mm
|
|
"bottom_margin": DXFAttr(41, default=20), # in mm
|
|
"right_margin": DXFAttr(42, default=7.5), # in mm
|
|
"top_margin": DXFAttr(43, default=20), # in mm
|
|
"paper_width": DXFAttr(44, default=420), # in mm
|
|
"paper_height": DXFAttr(45, default=297), # in mm
|
|
"plot_origin_x_offset": DXFAttr(46, default=0.0), # in mm
|
|
"plot_origin_y_offset": DXFAttr(47, default=0.0), # in mm
|
|
"plot_window_x1": DXFAttr(48, default=0.0),
|
|
"plot_window_y1": DXFAttr(49, default=0.0),
|
|
"plot_window_x2": DXFAttr(140, default=0.0),
|
|
"plot_window_y2": DXFAttr(141, default=0.0),
|
|
# Numerator of custom print scale: real world (paper) units:
|
|
"scale_numerator": DXFAttr(142, default=1.0),
|
|
# Denominator of custom print scale: drawing units:
|
|
"scale_denominator": DXFAttr(143, default=1.0),
|
|
# Plot layout flags:
|
|
# 1 = plot viewport borders
|
|
# 2 = show plot-styles
|
|
# 4 = plot centered
|
|
# 8 = plot hidden == hide paperspace entities?
|
|
# 16 = use standard scale
|
|
# 32 = plot with plot-styles
|
|
# 64 = scale lineweights
|
|
# 128 = plot entity lineweights
|
|
# 512 = draw viewports first
|
|
# 1024 = model type
|
|
# 2048 = update paper
|
|
# 4096 = zoom to paper on update
|
|
# 8192 = initializing
|
|
# 16384 = prev plot-init
|
|
# the "Plot transparencies" option is stored in the XDATA section
|
|
"plot_layout_flags": DXFAttr(70, default=688),
|
|
# Plot paper units:
|
|
# 0 = Plot in inches
|
|
# 1 = Plot in millimeters
|
|
# 2 = Plot in pixels
|
|
"plot_paper_units": DXFAttr(
|
|
72,
|
|
default=1,
|
|
validator=validator.is_in_integer_range(0, 3),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Plot rotation:
|
|
# 0 = No rotation
|
|
# 1 = 90 degrees counterclockwise
|
|
# 2 = Upside-down
|
|
# 3 = 90 degrees clockwise
|
|
"plot_rotation": DXFAttr(
|
|
73,
|
|
default=0,
|
|
validator=validator.is_in_integer_range(0, 4),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Plot type:
|
|
# 0 = Last screen display
|
|
# 1 = Drawing extents
|
|
# 2 = Drawing limits
|
|
# 3 = View specified by code 6
|
|
# 4 = Window specified by codes 48, 49, 140, and 141
|
|
# 5 = Layout information
|
|
"plot_type": DXFAttr(
|
|
74,
|
|
default=5,
|
|
validator=validator.is_in_integer_range(0, 6),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Associated CTB-file
|
|
"current_style_sheet": DXFAttr(7, default=""),
|
|
# Standard scale type:
|
|
# 0 = Scaled to Fit
|
|
# 1 = 1/128"=1'
|
|
# 2 = 1/64"=1'
|
|
# 3 = 1/32"=1'
|
|
# 4 = 1/16"=1'
|
|
# 5 = 3/32"=1'
|
|
# 6 = 1/8"=1'
|
|
# 7 = 3/16"=1'
|
|
# 8 = 1/4"=1'
|
|
# 9 = 3/8"=1'
|
|
# 10 = 1/2"=1'
|
|
# 11 = 3/4"=1'
|
|
# 12 = 1"=1'
|
|
# 13 = 3"=1'
|
|
# 14 = 6"=1'
|
|
# 15 = 1'=1'
|
|
# 16 = 1:1
|
|
# 17 = 1:2
|
|
# 18 = 1:4
|
|
# 19 = 1:8
|
|
# 20 = 1:10
|
|
# 21 = 1:16
|
|
# 22 = 1:20
|
|
# 23 = 1:30
|
|
# 24 = 1:40
|
|
# 25 = 1:50
|
|
# 26 = 1:100
|
|
# 27 = 2:1
|
|
# 28 = 4:1
|
|
# 29 = 8:1
|
|
# 30 = 10:1
|
|
# 31 = 100:1
|
|
# 32 = 1000:1
|
|
"standard_scale_type": DXFAttr(
|
|
75,
|
|
default=16,
|
|
validator=validator.is_in_integer_range(0, 33),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Shade plot mode:
|
|
# 0 = As Displayed
|
|
# 1 = Wireframe
|
|
# 2 = Hidden
|
|
# 3 = Rendered
|
|
"shade_plot_mode": DXFAttr(
|
|
76,
|
|
default=0,
|
|
validator=validator.is_in_integer_range(0, 4),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Shade plot resolution level:
|
|
# 0 = Draft
|
|
# 1 = Preview
|
|
# 2 = Normal
|
|
# 3 = Presentation
|
|
# 4 = Maximum
|
|
# 5 = Custom
|
|
"shade_plot_resolution_level": DXFAttr(
|
|
77,
|
|
default=2,
|
|
validator=validator.is_in_integer_range(0, 6),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Valid range: 100 to 32767, Only applied when the shade_plot_resolution
|
|
# level is set to 5 (Custom)
|
|
"shade_plot_custom_dpi": DXFAttr(
|
|
78,
|
|
default=300,
|
|
validator=validator.is_in_integer_range(100, 32768),
|
|
fixer=validator.fit_into_integer_range(100, 32768),
|
|
),
|
|
# Factor for unit conversion (mm -> inches)
|
|
# 147: DXF Reference error: 'A floating point scale factor that represents
|
|
# the standard scale value specified in code 75'
|
|
"unit_factor": DXFAttr(
|
|
147,
|
|
default=1.0,
|
|
validator=validator.is_greater_zero,
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
"paper_image_origin_x": DXFAttr(148, default=0),
|
|
"paper_image_origin_y": DXFAttr(149, default=0),
|
|
"shade_plot_handle": DXFAttr(333, optional=True),
|
|
},
|
|
)
|
|
acdb_plot_settings_group_codes = group_code_mapping(acdb_plot_settings)
|
|
|
|
# The "Plot transparencies" option is stored in the XDATA section of the
|
|
# LAYOUT entity:
|
|
# 1001
|
|
# PLOTTRANSPARENCY
|
|
# 1071
|
|
# 1
|
|
|
|
|
|
@register_entity
|
|
class PlotSettings(DXFObject):
|
|
DXFTYPE = "PLOTSETTINGS"
|
|
DXFATTRIBS = DXFAttributes(base_class, acdb_plot_settings)
|
|
|
|
def load_dxf_attribs(
|
|
self, processor: Optional[SubclassProcessor] = None
|
|
) -> DXFNamespace:
|
|
dxf = super().load_dxf_attribs(processor)
|
|
if processor:
|
|
processor.fast_load_dxfattribs(dxf, acdb_plot_settings_group_codes, 1)
|
|
return dxf
|
|
|
|
def export_entity(self, tagwriter: AbstractTagWriter) -> None:
|
|
"""Export entity specific data as DXF tags."""
|
|
super().export_entity(tagwriter)
|
|
tagwriter.write_tag2(SUBCLASS_MARKER, acdb_plot_settings.name)
|
|
|
|
self.dxf.export_dxf_attribs(
|
|
tagwriter,
|
|
[
|
|
"page_setup_name",
|
|
"plot_configuration_file",
|
|
"paper_size",
|
|
"plot_view_name",
|
|
"left_margin",
|
|
"bottom_margin",
|
|
"right_margin",
|
|
"top_margin",
|
|
"paper_width",
|
|
"paper_height",
|
|
"plot_origin_x_offset",
|
|
"plot_origin_y_offset",
|
|
"plot_window_x1",
|
|
"plot_window_y1",
|
|
"plot_window_x2",
|
|
"plot_window_y2",
|
|
"scale_numerator",
|
|
"scale_denominator",
|
|
"plot_layout_flags",
|
|
"plot_paper_units",
|
|
"plot_rotation",
|
|
"plot_type",
|
|
"current_style_sheet",
|
|
"standard_scale_type",
|
|
"shade_plot_mode",
|
|
"shade_plot_resolution_level",
|
|
"shade_plot_custom_dpi",
|
|
"unit_factor",
|
|
"paper_image_origin_x",
|
|
"paper_image_origin_y",
|
|
],
|
|
)
|
|
|
|
def register_resources(self, registry: xref.Registry) -> None:
|
|
super().register_resources(registry)
|
|
registry.add_handle(self.dxf.get("shade_plot_handle"))
|
|
|
|
def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None:
|
|
super().map_resources(clone, mapping)
|
|
shade_plot_handle = self.dxf.get("shade_plot_handle")
|
|
if shade_plot_handle and shade_plot_handle != "0":
|
|
clone.dxf.shade_plot_handle = mapping.get_handle(shade_plot_handle)
|
|
else:
|
|
clone.dxf.discard("shade_plot_handle")
|
|
|
|
|
|
acdb_layout = DefSubclass(
|
|
"AcDbLayout",
|
|
{
|
|
# Layout name:
|
|
"name": DXFAttr(1, default="Layoutname"),
|
|
# Flag (bit-coded) to control the following:
|
|
# 1 = Indicates the PSLTSCALE value for this layout when this layout is current
|
|
# 2 = Indicates the LIMCHECK value for this layout when this layout is current
|
|
"layout_flags": DXFAttr(70, default=1),
|
|
# Tab order: This number is an ordinal indicating this layout's ordering in
|
|
# the tab control that is attached to the AutoCAD drawing frame window.
|
|
# Note that the "Model" tab always appears as the first tab regardless of
|
|
# its tab order.
|
|
"taborder": DXFAttr(71, default=1),
|
|
# Minimum limits:
|
|
"limmin": DXFAttr(10, xtype=XType.point2d, default=Vec2(0, 0)),
|
|
# Maximum limits:
|
|
"limmax": DXFAttr(11, xtype=XType.point2d, default=Vec2(420, 297)),
|
|
# Insertion base point for this layout:
|
|
"insert_base": DXFAttr(12, xtype=XType.point3d, default=NULLVEC),
|
|
# Minimum extents for this layout:
|
|
"extmin": DXFAttr(14, xtype=XType.point3d, default=Vec3(1e20, 1e20, 1e20)),
|
|
# Maximum extents for this layout:
|
|
"extmax": DXFAttr(15, xtype=XType.point3d, default=Vec3(-1e20, -1e20, -1e20)),
|
|
"elevation": DXFAttr(146, default=0.0),
|
|
"ucs_origin": DXFAttr(13, xtype=XType.point3d, default=NULLVEC),
|
|
"ucs_xaxis": DXFAttr(
|
|
16,
|
|
xtype=XType.point3d,
|
|
default=X_AXIS,
|
|
validator=validator.is_not_null_vector,
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
"ucs_yaxis": DXFAttr(
|
|
17,
|
|
xtype=XType.point3d,
|
|
default=Y_AXIS,
|
|
validator=validator.is_not_null_vector,
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Orthographic type of UCS:
|
|
# 0 = UCS is not orthographic
|
|
# 1 = Top
|
|
# 2 = Bottom
|
|
# 3 = Front
|
|
# 4 = Back
|
|
# 5 = Left
|
|
# 6 = Right
|
|
"ucs_type": DXFAttr(
|
|
76,
|
|
default=1,
|
|
validator=validator.is_in_integer_range(0, 7),
|
|
fixer=RETURN_DEFAULT,
|
|
),
|
|
# Handle of parent BLOCK_RECORD
|
|
"block_record_handle": DXFAttr(330),
|
|
# Handle to the viewport that was last active in this
|
|
# layout when the layout was current:
|
|
"viewport_handle": DXFAttr(331),
|
|
# Handle of AcDbUCSTableRecord if UCS is a named
|
|
# UCS. If not present, then UCS is unnamed
|
|
"ucs_handle": DXFAttr(345),
|
|
# Handle of AcDbUCSTableRecord of base UCS if UCS is
|
|
# orthographic (76 code is non-zero). If not present and
|
|
# 76 code is non-zero, then base UCS is taken to be WORLD
|
|
"base_ucs_handle": DXFAttr(346),
|
|
},
|
|
)
|
|
acdb_layout_group_codes = group_code_mapping(acdb_layout)
|
|
|
|
|
|
@register_entity
|
|
class DXFLayout(PlotSettings):
|
|
DXFTYPE = "LAYOUT"
|
|
DXFATTRIBS = DXFAttributes(base_class, acdb_plot_settings, acdb_layout)
|
|
|
|
def load_dxf_attribs(
|
|
self, processor: Optional[SubclassProcessor] = None
|
|
) -> DXFNamespace:
|
|
dxf = super().load_dxf_attribs(processor)
|
|
if processor:
|
|
processor.fast_load_dxfattribs(dxf, acdb_layout_group_codes, 2)
|
|
return dxf
|
|
|
|
def export_entity(self, tagwriter: AbstractTagWriter) -> None:
|
|
# Set correct model type flag
|
|
self.set_flag_state(1024, self.dxf.name.upper() == "MODEL", "plot_layout_flags")
|
|
super().export_entity(tagwriter)
|
|
tagwriter.write_tag2(SUBCLASS_MARKER, acdb_layout.name)
|
|
self.dxf.export_dxf_attribs(
|
|
tagwriter,
|
|
[
|
|
"name",
|
|
"layout_flags",
|
|
"taborder",
|
|
"limmin",
|
|
"limmax",
|
|
"insert_base",
|
|
"extmin",
|
|
"extmax",
|
|
"elevation",
|
|
"ucs_origin",
|
|
"ucs_xaxis",
|
|
"ucs_yaxis",
|
|
"ucs_type",
|
|
"block_record_handle",
|
|
"viewport_handle",
|
|
"ucs_handle",
|
|
"base_ucs_handle",
|
|
],
|
|
)
|
|
|
|
def register_resources(self, registry: xref.Registry) -> None:
|
|
super().register_resources(registry)
|
|
registry.add_handle(self.dxf.get("ucs_handle"))
|
|
registry.add_handle(self.dxf.get("base_ucs_handle"))
|
|
|
|
def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None:
|
|
super().map_resources(clone, mapping)
|
|
|
|
# The content of paperspace layouts is not copied automatically and the
|
|
# associated BLOCK_RECORD is created and assigned in a special method.
|
|
mapping.map_existing_handle(self, clone, "ucs_handle", optional=True)
|
|
mapping.map_existing_handle(self, clone, "base_ucs_handle", optional=True)
|
|
mapping.map_existing_handle(self, clone, "viewport_handle", optional=True)
|