/ pdkmaster / dispatch / shape.py
shape.py
  1  # SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-or-later OR CERN-OHL-S-2.0+ OR Apache-2.0
  2  from typing import Optional, Callable
  3  
  4  from ..technology import geometry as _geo
  5  
  6  
  7  class ShapeDispatcher:
  8      """Dispatch to class method based on type of `_Shape` subclasses.
  9  
 10      This dispatcher follows the common way of working in the `dispatch` module.
 11      Exception is the "geometry.MultiPartShape._Part", for this one can overload
 12      the `MultiPartShape__Part` method. The default implementation with call the
 13      dispatcher on the `part_shape` of the given object. Assume that dispatcher is
 14      called with a `MultiPartShape._Part` with object `part` with `part.part_shape`
 15      of type `Rect`. Then the default implement will call the `Rect` method with
 16      `part.part_shape` as shape.
 17      """
 18      def __init__(self):
 19          self._parent_call: Optional[Callable] = None
 20  
 21      def __call__(self, shape: _geo._Shape, *args, **kwargs):
 22          # Reset _parent_call
 23          self._parent_call = None
 24  
 25          if isinstance(shape, _geo.MultiPartShape._Part):
 26              classname = "MultiPartShape__Part"
 27          else:
 28              classname = shape.__class__.__name__.split(".")[-1]
 29          return getattr(self, classname, self._pd_unhandled)(shape, *args, **kwargs)
 30  
 31      def _pd_unhandled(self, shape: _geo._Shape, *args, **kwargs):
 32          raise RuntimeError(
 33              "Internal error: unhandled dispatcher for object of type "
 34              f"{shape.__class__.__name__}"
 35          )
 36  
 37      def _Shape(self, shape: _geo._Shape, *args, **kwargs):
 38          """This for the base class and by default raises NotImplementedError
 39          """
 40          raise NotImplementedError(
 41              f"No dispatcher implemented for object of type {shape.__class__.__name__}"
 42          )
 43  
 44      def _Rectangular(self, shape: _geo._Rectangular, *args, **kwargs):
 45          return self._Shape(shape, *args, **kwargs)
 46  
 47      def _PointsShape(self,
 48          shape: _geo._PointsShape, *args, **kwargs,
 49      ):
 50          if self._parent_call is None:
 51              call = self._Shape
 52          else:
 53              call = self._parent_call
 54              self._parent_call = None
 55          return call(shape, *args, **kwargs)
 56  
 57      def Point(self, point: _geo.Point, *args, **kwargs):
 58          self._parent_call = self._Rectangular
 59          return self._PointsShape(point, *args, **kwargs)
 60  
 61      def Line(self, line: _geo.Line, *args, **kwargs):
 62          self._parent_call = self._Rectangular
 63          return self._PointsShape(line, *args, **kwargs)
 64  
 65      def Polygon(self,
 66          polygon: _geo.Polygon, *args, **kwargs,
 67      ):
 68          # _parent_call is kept and used in self._PointsShape
 69          return self._PointsShape(polygon, *args, **kwargs)
 70  
 71      def Rect(self, rect: _geo.Rect, *args, **kwargs):
 72          self._parent_call = self._Rectangular
 73          return self.Polygon(rect, *args, **kwargs)
 74  
 75      def MultiPath(self, mp: _geo.MultiPath, *args, **kwargs):
 76          return self.Polygon(mp, *args, **kwargs)
 77  
 78      def Ring(self, ring: _geo.Ring, *args, **kwargs):
 79          return self.MultiPath(ring, *args, **kwargs)
 80  
 81      def RectRing(self, ring: _geo.RectRing, *args, **kwargs):
 82          return self._Shape(ring, *args, **kwargs)
 83  
 84      def Label(self, label: _geo.Label, *args, **kwargs):
 85          return self._Shape(label, *args, **kwargs)
 86  
 87      def MultiPartShape(self, mps: _geo.MultiPartShape, *args, **kwargs):
 88          return self.Polygon(mps, *args, **kwargs)
 89  
 90      def MultiPartShape__Part(self, part: _geo.MultiPartShape._Part, *args, **kwargs):
 91          return self(part._partshape, *args, **kwargs)
 92  
 93      def MultiShape(self, ms: _geo.MultiShape, *args, **kwargs):
 94          return self._Shape(ms, *args, **kwargs)
 95  
 96      def RepeatedShape(self, rs: _geo.RepeatedShape, *args, **kwargs):
 97          return self._Shape(rs, *args, **kwargs)
 98  
 99      def ArrayShape(self, array: _geo.ArrayShape, *args, **kwargs):
100          return self.RepeatedShape(array, *args, **kwargs)