1# Copyright (c) 2020, Manfred Moitzi 2# License: MIT License 3from typing import Sequence, Optional 4import abc 5from ezdxf.math import Vec3 6from .backend import Backend 7from .properties import Properties 8 9 10class AbstractLineRenderer: 11 """ The line rendering class should get all options from the backend, so a 12 change in the backend is also applied by the line renderer e.g. disable 13 lineweight or linetype rendering. 14 """ 15 16 def __init__(self, backend: Backend): 17 self._pattern_cache = dict() 18 self._backend = backend 19 20 @abc.abstractmethod 21 def draw_line(self, start: Vec3, end: Vec3, 22 properties: Properties, z: float): 23 ... 24 25 @abc.abstractmethod 26 def draw_path(self, path, properties: Properties, z: float): 27 ... 28 29 @property 30 def linetype_scaling(self) -> float: 31 return self._backend.linetype_scaling 32 33 @property 34 def lineweight_scaling(self) -> float: 35 return self._backend.lineweight_scaling 36 37 @property 38 def min_lineweight(self) -> float: 39 return self._backend.min_lineweight 40 41 @property 42 def min_dash_length(self) -> float: 43 return self._backend.min_dash_length 44 45 @property 46 def max_flattening_distance(self) -> float: 47 return self._backend.max_flattening_distance 48 49 @property 50 def measurement(self) -> float: 51 return self._backend.measurement 52 53 @property 54 def measurement_scale(self) -> float: 55 """ Returns internal linetype scaling factor. """ 56 return 1.0 57 58 def pattern(self, properties: Properties) -> Sequence[float]: 59 """ Get pattern - implements pattern caching. """ 60 scale = (self.measurement_scale * self.linetype_scaling * 61 properties.linetype_scale) 62 key = (properties.linetype_name, scale) 63 pattern_ = self._pattern_cache.get(key) 64 if pattern_ is None: 65 pattern_ = self.create_pattern(properties, scale) 66 self._pattern_cache[key] = pattern_ 67 return pattern_ 68 69 def create_pattern(self, properties: Properties, 70 scale: float) -> Sequence[float]: 71 """ Returns simplified linetype tuple: on_off_sequence """ 72 # only matplotlib needs a different pattern definition 73 if len(properties.linetype_pattern) < 2: 74 # Do not return None -> None indicates: "not cached" 75 return tuple() 76 else: 77 min_dash_length = self.min_dash_length 78 pattern = [max(e * scale, min_dash_length) for e in 79 properties.linetype_pattern] 80 if len(pattern) % 2: 81 pattern.pop() 82 return pattern 83 84 def lineweight(self, properties: Properties) -> float: 85 """ Set lineweight_scaling=0 to use a constant minimal lineweight. """ 86 return max( 87 properties.lineweight * self.lineweight_scaling, 88 self.min_lineweight 89 ) 90 91 def linetype(self, properties: Properties) -> Optional[Sequence[float]]: 92 """ Set linetype_scaling=0 to disable linetype rendering. 93 94 Returns ``None`` to disable linetype rendering. 95 96 """ 97 if self.linetype_scaling: 98 return self.pattern(properties) 99 else: 100 return None 101