Passed
Pull Request — master (#21)
by Matt
03:47 queued 01:54
created

Fixture.design_render()   C

Complexity

Conditions 10

Size

Total Lines 75
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 38
nop 2
dl 0
loc 75
rs 5.9999
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like PyDMXControl.design.parts._Fixture.Fixture.design_render() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
 *  PyDMXControl: A Python 3 module to control DMX using uDMX.
3
 *                Featuring fixture profiles, built-in effects and a web control panel.
4
 *  <https://github.com/MattIPv4/PyDMXControl/>
5
 *  Copyright (C) 2018 Matt Cowley (MattIPv4) ([email protected])
6
"""
7
8
from math import floor
9
from typing import Union, List, Tuple
10
11
import pygame
12
13
from ._Part import Part
14
from ._Text import Text
15
from .data import load
16
from .._screen import Screen
17
18
19
class Fixture(Part):
20
21
    def __init__(self, x: Union[int, float], y: Union[int, float], name: str = "", rotation: Union[int, float] = 0, *,
22
                 outline_color: Union[List[int], Tuple[int, int, int]] = (0, 0, 0),
23
                 fill_color: Union[List[int], Tuple[int, int, int]] = (255, 255, 255),
24
                 label: str = "", scale: float = 1, align_left: bool = False):
25
        super().__init__()
26
        self.__rotation = rotation
27
        self.__name = name
28
        self.__data = load(name)
29
        self.__outline = outline_color
30
        self.__fill = fill_color
31
        self.__label = Text(0, 0, label, scale=scale) if label else None
32
        self.__scale = scale
33
        self.__size = 0.06 * self.__scale
34
        self.__left = align_left
35
        self.set_pos(x, y)
36
37
    def design_render(self, screen: Screen) -> Tuple[int, int, pygame.Surface]:
38
        # Get points from fixture else rectangle
39
        raw_points = self.__data[2] if self.__data else [[0, 0, 0], [30, 0, 1], [30, 10, 1], [0, 10, 1]]
40
41
        # Get largest x/y
42
        maxx = max([f[0] for f in raw_points])
43
        maxy = max([f[1] for f in raw_points])
44
45
        # Split the points up into their line groups
46
        pen = 6
47
        points = []
48
        for point in raw_points:
49
            if point[2] == 0:
50
                points.append([])
51
            points[-1].append([point[0] + pen, point[1] + pen])
52
53
        # Generate the surface
54
        surface = pygame.Surface((maxx + (pen * 2), maxy + (pen * 2)), pygame.SRCALPHA, 32)
55
        surface = surface.convert_alpha()
56
57
        # Draw each line group filled
58
        for point_set in points:
59
            if len(point_set) > 2:
60
                pygame.draw.polygon(surface, self.__fill, point_set)
61
62
        # Draw each line group outline
63
        for point_set in points:
64
            if len(point_set) > 1:
65
                pygame.draw.lines(surface, self.__outline, True, point_set, pen)
66
67
        # Resize
68
        """max_size = self.__size
69
        x, y = surface.get_size()
70
        if x > y:
71
            y = y * (max_size / x)
72
            x = max_size
73
        else:
74
            x = x * (max_size / y)
75
            y = max_size
76
        x, y = int(x), int(y)
77
        surface = pygame.transform.scale(surface, (x * screen.block_size, y * screen.block_size))"""
78
        x, y = surface.get_size()
79
        surface = pygame.transform.scale(surface, (
80
            int(x * self.__size * screen.block_size), int(y * self.__size * screen.block_size)))
81
82
        # Rotate
83
        surface = pygame.transform.rotate(surface, int(self.__rotation))
84
85
        # Calc pos
86
        x, y = surface.get_size()
87
        x = int((self._x * screen.block_size) - floor(x / 2))
88
        y = int((self._y * screen.block_size) - floor(y / 2))
89
        if self.__left:
90
            x = int(self._x * screen.block_size)
91
92
        # Text label
93
        if self.__label is not None:
94
            # Generate text
95
            text = self.__label.design_render(screen)[2]
96
97
            # Add to full
98
            tx, ty = text.get_size()
99
            fx, fy = surface.get_size()
100
            new_surface = pygame.Surface((max(fx, tx + fx * (3 / 4)), max(ty, fy + ty)), pygame.SRCALPHA, 32)
101
            new_surface = new_surface.convert_alpha()
102
            new_surface.blit(surface, (0, new_surface.get_height() - fy))
103
            new_surface.blit(text, (fx * (3 / 4), 0))
104
105
            # Update pos
106
            y -= (new_surface.get_height() - fy)
107
        else:
108
            new_surface = surface
109
110
        # Render
111
        return x, y, new_surface
112