File size: 6,394 Bytes
26f7fa0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
"""
MLSTRUCT-FP - DB - C

Base FP components.
"""

__all__ = ['BaseComponent', 'BasePolyComponent', 'BasePolyObj']

import abc
import matplotlib.pyplot as plt
import plotly.graph_objects as go

from MLStructFP.utils import GeomPoint2D
from MLStructFP._types import List, TYPE_CHECKING, VectorInstance, NumberType, Dict

if TYPE_CHECKING:
    from MLStructFP.db._floor import Floor


class BaseComponent(abc.ABC):
    """
    Floor plan base component.
    """
    _floor: 'Floor'
    _id: int
    _points: List['GeomPoint2D']  # The coordinates of the object

    def __init__(
            self,
            component_id: int,
            x: List[float],
            y: List[float],
            floor: 'Floor'
    ) -> None:
        """
        Constructor.

        :param component_id: ID of the component
        :param x: List of coordinates within x-axis
        :param y: List of coordinates within y-axis
        :param floor: Floor object
        """
        assert isinstance(component_id, int) and component_id > 0
        assert isinstance(x, VectorInstance) and len(x) > 0
        assert isinstance(y, VectorInstance) and len(y) == len(x)
        self._floor = floor
        self._id = component_id
        self._points = []
        for i in range(len(x)):
            self._points.append(GeomPoint2D(float(x[i]), float(y[i])))

    @property
    def floor(self) -> 'Floor':
        return self._floor

    @property
    def id(self) -> int:
        return self._id

    @property
    def points(self) -> List['GeomPoint2D']:
        return [p for p in self._points]

    def plot_plotly(self, *args, **kwargs) -> None:
        """
        Plot rect.
        """
        raise NotImplementedError

    def plot_matplotlib(self, *args, **kwargs) -> None:
        """
        Plot simple using matplotlib.
        """
        raise NotImplementedError


class BasePolyComponent(BaseComponent, abc.ABC):
    """
    Polygonal-type base component.
    """

    def __svg_path(self, dx: NumberType = 0, dy: NumberType = 0) -> str:
        """
        Get svg path for plotting the object.

        :return: SVG path string
        :param dx: X displacement
        :param dy: Y displacement
        """
        px, py = [p.x for p in self._points], [p.y for p in self._points]
        for i in range(len(px)):  # Adds displacement (dx, dy)
            px[i] += dx
            py[i] += dy
        svg = f'M {px[0]},{py[0]}'
        for i in range(1, len(px)):
            svg += f' L{px[i]},{py[i]}'
        svg += ' Z'
        return svg

    # noinspection PyUnusedLocal
    def plot_plotly(
            self,
            fig: 'go.Figure',
            dx: NumberType,
            dy: NumberType,
            opacity: NumberType,
            color: str,
            name: str,
            **kwargs
    ) -> None:
        """
        Plot polygon object.

        :param fig: Figure object
        :param dx: X displacement
        :param dy: Y displacement
        :param opacity: Object opacity
        :param color: Color
        :param name: Object name
        :param kwargs: Optional keyword arguments
        """
        _path = self.__svg_path(dx=dx, dy=dy)
        fig.add_shape(
            fillcolor=color,
            line_color=color,
            name=name,
            opacity=opacity,
            path=_path,
            type='path'
        )

    def plot_matplotlib(
            self,
            ax: 'plt.Axes',
            linewidth: NumberType,
            alpha: NumberType,
            color: str,
            fill: bool
    ) -> None:
        """
        Plot simple using matplotlib.

        :param ax: Matplotlib axes reference
        :param linewidth: Plot linewidth
        :param alpha: Alpha transparency value (0-1)
        :param color: Plot color
        :param fill: Fill object
        """
        px, py = [p.x for p in self._points], [p.y for p in self._points]
        px.append(px[0])
        py.append(py[0])
        if fill:
            ax.fill(px, py, color=color, lw=None, alpha=alpha)
        else:
            ax.plot(px, py, '-', color=color, linewidth=linewidth, alpha=alpha)


class BasePolyObj(BasePolyComponent, abc.ABC):
    """
    FP base polygon object.
    """
    __basename: str
    __color: str
    _category: int
    _category_name: str

    def __init__(
            self,
            ctx: Dict[int, 'BasePolyObj'],
            basename: str,
            obj_id: int,
            floor: 'Floor',
            x: List[float],
            y: List[float],
            color: str,
            category: int,
            category_name: str,
    ) -> None:
        """
        Constructor.

        :param ctx: Polygon object context
        :param basename: Basename
        :param obj_id: ID of the object
        :param floor: Floor object
        :param x: List of coordinates within x-axis
        :param y: List of coordinates within y-axis
        :param color: Object color
        :param category: Object category
        :param category_name: Object category name
        """
        BasePolyComponent.__init__(self, obj_id, x, y, floor)
        ctx[obj_id] = self
        self.__basename = basename
        self.__color = color
        self._category_name = category_name
        self._category = category

    @property
    def category(self) -> int:
        return self._category

    @property
    def category_name(self) -> str:
        return self._category_name

    # noinspection PyUnusedLocal
    def plot_plotly(
            self,
            fig: 'go.Figure',
            dx: NumberType = 0,
            dy: NumberType = 0,
            postname: str = '',
            opacity: NumberType = 0.2,
            color: str = '',
            name: str = '',
            **kwargs
    ) -> None:
        if name != '':
            name = f'{name} '
        super().plot_plotly(
            fig, dx, dy, opacity, self.__color if color == '' else color,
            '' if self.category_name == '' else f'[{self.category}] ' + f'{self.__basename} {name}ID{self.id}{postname}',
            **kwargs)

    def plot_matplotlib(
            self,
            ax: 'plt.Axes',
            linewidth: NumberType = 2.0,
            alpha: NumberType = 1.0,
            color: str = '',
            fill: bool = True
    ) -> None:
        super().plot_matplotlib(ax, linewidth, alpha, self.__color if color == '' else color, fill)