176 lines
5.3 KiB
Python
176 lines
5.3 KiB
Python
# Copyright (c) 2023, Manfred Moitzi
|
|
# License: MIT License
|
|
from __future__ import annotations
|
|
import dataclasses
|
|
import enum
|
|
import copy
|
|
from ezdxf.colors import RGB
|
|
|
|
|
|
class FillType(enum.IntEnum):
|
|
"""Fill type enumeration."""
|
|
|
|
NONE = 0
|
|
SOLID = 1
|
|
HATCHING = 2
|
|
CROSS_HATCHING = 3
|
|
SHADING = 4
|
|
|
|
|
|
class FillMethod(enum.IntEnum):
|
|
"""Fill method enumeration."""
|
|
|
|
EVEN_ODD = 0
|
|
NON_ZERO_WINDING = 1
|
|
|
|
|
|
RGB_NONE = RGB(-1, -1, -1)
|
|
RGB_BLACK = RGB(0, 0, 0)
|
|
RGB_WHITE = RGB(255, 255, 255)
|
|
LIGHT_GREY = RGB(200, 200, 200)
|
|
|
|
|
|
@dataclasses.dataclass
|
|
class Pen:
|
|
"""Represents a pen table entry."""
|
|
|
|
index: int
|
|
width: float # in mm
|
|
color: RGB
|
|
|
|
|
|
class Properties:
|
|
"""Consolidated display properties."""
|
|
|
|
DEFAULT_PEN = Pen(1, 0.35, RGB_NONE)
|
|
|
|
def __init__(self) -> None:
|
|
# hashed content
|
|
self.pen_index: int = 1
|
|
self.pen_color = RGB_NONE
|
|
self.pen_width: float = 0.35 # in mm
|
|
self.fill_type = FillType.SOLID
|
|
self.fill_method = FillMethod.EVEN_ODD
|
|
self.fill_hatch_line_angle: float = 0.0 # in degrees
|
|
self.fill_hatch_line_spacing: float = 40.0 # in plotter units
|
|
self.fill_shading_density: float = 100.0
|
|
# not hashed content
|
|
self.max_pen_count: int = 2
|
|
self.pen_table: dict[int, Pen] = {}
|
|
self.reset()
|
|
|
|
def hash(self) -> int:
|
|
return hash(
|
|
(
|
|
self.pen_index,
|
|
self.pen_color,
|
|
self.pen_width,
|
|
self.fill_type,
|
|
self.fill_method,
|
|
self.fill_hatch_line_angle,
|
|
self.fill_hatch_line_spacing,
|
|
self.fill_shading_density,
|
|
)
|
|
)
|
|
|
|
def copy(self) -> Properties:
|
|
# the pen table is shared across all copies of Properties
|
|
return copy.copy(self)
|
|
|
|
def setup_default_pen_table(self):
|
|
if len(self.pen_table):
|
|
return
|
|
pens = self.pen_table
|
|
width = self.DEFAULT_PEN.width
|
|
pens[0] = Pen(0, width, RGB(255, 255, 255)) # white
|
|
pens[1] = Pen(1, width, RGB(0, 0, 0)) # black
|
|
pens[2] = Pen(2, width, RGB(255, 0, 0)) # red
|
|
pens[3] = Pen(3, width, RGB(0, 255, 0)) # green
|
|
pens[4] = Pen(4, width, RGB(255, 255, 0)) # yellow
|
|
pens[5] = Pen(5, width, RGB(0, 0, 255)) # blue
|
|
pens[6] = Pen(6, width, RGB(255, 0, 255)) # magenta
|
|
pens[7] = Pen(6, width, RGB(0, 255, 255)) # cyan
|
|
|
|
def reset(self) -> None:
|
|
self.max_pen_count = 2
|
|
self.pen_index = self.DEFAULT_PEN.index
|
|
self.pen_color = self.DEFAULT_PEN.color
|
|
self.pen_width = self.DEFAULT_PEN.width
|
|
self.pen_table = {}
|
|
self.fill_type = FillType.SOLID
|
|
self.fill_method = FillMethod.EVEN_ODD
|
|
self.fill_hatch_line_angle = 0.0
|
|
self.fill_hatch_line_spacing = 40.0
|
|
self.fill_shading_density = 1.0
|
|
self.setup_default_pen_table()
|
|
|
|
def get_pen(self, index: int) -> Pen:
|
|
return self.pen_table.get(index, self.DEFAULT_PEN)
|
|
|
|
def set_max_pen_count(self, count: int) -> None:
|
|
self.max_pen_count = count
|
|
|
|
def set_current_pen(self, index: int) -> None:
|
|
self.pen_index = index
|
|
pen = self.get_pen(index)
|
|
self.pen_width = pen.width
|
|
self.pen_color = pen.color
|
|
|
|
def set_pen_width(self, index: int, width: float) -> None:
|
|
if index == -1:
|
|
self.pen_width = width
|
|
else:
|
|
pen = self.pen_table.setdefault(
|
|
index, Pen(index, width, self.DEFAULT_PEN.color)
|
|
)
|
|
pen.width = width
|
|
|
|
def set_pen_color(self, index: int, rgb: RGB) -> None:
|
|
if index == -1:
|
|
self.pen_color = rgb
|
|
else:
|
|
pen = self.pen_table.setdefault(
|
|
index, Pen(index, self.DEFAULT_PEN.width, rgb)
|
|
)
|
|
pen.color = rgb
|
|
|
|
def set_fill_type(self, fill_type: int, spacing: float, angle: float):
|
|
if fill_type == 3:
|
|
self.fill_type = FillType.HATCHING
|
|
self.fill_hatch_line_spacing = spacing
|
|
self.fill_hatch_line_angle = angle
|
|
elif fill_type == 4:
|
|
self.fill_type = FillType.CROSS_HATCHING
|
|
self.fill_hatch_line_spacing = spacing
|
|
self.fill_hatch_line_angle = angle
|
|
elif fill_type == 10:
|
|
self.fill_type = FillType.SHADING
|
|
self.fill_shading_density = spacing
|
|
else:
|
|
self.fill_type = FillType.SOLID
|
|
|
|
def set_fill_method(self, fill_method: int) -> None:
|
|
self.fill_method = FillMethod(fill_method)
|
|
|
|
def resolve_pen_color(self) -> RGB:
|
|
"""Returns the final RGB pen color."""
|
|
rgb = self.pen_color
|
|
if rgb is RGB_NONE:
|
|
pen = self.pen_table.get(self.pen_index, self.DEFAULT_PEN)
|
|
rgb = pen.color
|
|
if rgb is RGB_NONE:
|
|
return RGB_BLACK
|
|
return rgb
|
|
|
|
def resolve_fill_color(self) -> RGB:
|
|
"""Returns the final RGB fill color."""
|
|
ft = self.fill_type
|
|
if ft == FillType.SOLID:
|
|
return self.resolve_pen_color()
|
|
elif ft == FillType.SHADING:
|
|
grey = min(int(2.55 * (100.0 - self.fill_shading_density)), 255)
|
|
return RGB(grey, grey, grey)
|
|
elif ft == FillType.HATCHING or ft == FillType.CROSS_HATCHING:
|
|
return LIGHT_GREY
|
|
return RGB_WHITE
|