Completed
Push — master ( e9e2ae...b6e5e0 )
by Kyle
01:34
created

Noise._setstate_old()   A

Complexity

Conditions 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
dl 0
loc 17
rs 9.4285
1
"""
2
The :any:`Noise.sample_mgrid` and :any:`Noise.sample_ogrid` methods are
3
multi-threaded operations when the Python runtime supports OpenMP.
4
Even when single threaded these methods will perform much better than
5
multiple calls to :any:`Noise.get_point`.
6
7
Example::
8
9
    import numpy as np
10
    import tcod
11
    import tcod.noise
12
13
    noise = tcod.noise.Noise(
14
        dimensions=2,
15
        algorithm=tcod.NOISE_SIMPLEX,
16
        implementation=tcod.noise.TURBULENCE,
17
        hurst=0.5,
18
        lacunarity=2.0,
19
        octaves=4,
20
        rand=None,
21
        )
22
23
    # Create a 5x5 open multi-dimensional mesh-grid.
24
    ogrid = [np.arange(5, dtype=np.float32),
25
             np.arange(5, dtype=np.float32)]
26
    print(ogrid)
27
28
    # Scale the grid.
29
    ogrid[0] *= 0.25
30
    ogrid[1] *= 0.25
31
32
    # Return the sampled noise from this grid of points.
33
    samples = noise.sample_ogrid(ogrid)
34
    print(samples)
35
"""
36
from __future__ import absolute_import
37
38
import operator
0 ignored issues
show
Unused Code introduced by
The import operator seems to be unused.
Loading history...
39
40
import numpy as np
0 ignored issues
show
Configuration introduced by
The import numpy could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
41
42
from tcod.tcod import _cdata
0 ignored issues
show
Unused Code introduced by
Unused _cdata imported from tcod.tcod
Loading history...
43
from tcod.libtcod import ffi, lib
44
import tcod.libtcod
45
46
"""Noise implementation constants"""
0 ignored issues
show
Unused Code introduced by
This string statement has no effect and could be removed.
Loading history...
47
SIMPLE = 0
48
FBM = 1
49
TURBULENCE = 2
50
51
class Noise(object):
52
    """
53
54
    The ``hurst`` exponent describes the raggedness of the resultant noise,
55
    with a higher value leading to a smoother noise.
56
    Not used with tcod.noise.SIMPLE.
57
58
    ``lacunarity`` is a multiplier that determines how fast the noise
59
    frequency increases for each successive octave.
60
    Not used with tcod.noise.SIMPLE.
61
62
    Args:
63
        dimensions (int): Must be from 1 to 4.
64
        algorithm (int): Defaults to NOISE_SIMPLEX
65
        implementation (int): Defaults to tcod.noise.SIMPLE
66
        hurst (float): The hurst exponent.  Should be in the 0.0-1.0 range.
67
        lacunarity (float): The noise lacunarity.
68
        octaves (float): The level of detail on fBm and turbulence
69
                         implementations.
70
        rand (Optional[Random]): A Random instance, or None.
71
72
    Attributes:
73
        noise_c (CData): A cffi pointer to a TCOD_noise_t object.
74
            .. versionadded:: 2.5
75
76
    .. versionadded:: 2.0
77
    """
78
79
    def __init__(self, dimensions, algorithm=2, implementation=SIMPLE,
80
                 hurst=0.5, lacunarity=2.0, octaves=4, rand=None):
81
        if not 0 < dimensions <= 4:
82
            raise ValueError('dimensions must be in range 0 < n <= 4, got %r' %
83
                             (dimensions,))
84
        self._random = rand
85
        _random_c = rand.random_c if rand else ffi.NULL
86
        self._algorithm = algorithm
87
        self.noise_c = ffi.gc(
88
            ffi.cast(
89
                'perlin_data_t*',
90
                lib.TCOD_noise_new(dimensions, hurst, lacunarity,
91
                                   _random_c),
92
                ),
93
            lib.TCOD_noise_delete)
94
        self._tdl_noise_c = ffi.new('TDLNoise*', (self.noise_c,
95
                                                  dimensions,
96
                                                  0,
97
                                                  octaves))
98
        self.implementation = implementation # sanity check
99
100
    @property
101
    def dimensions(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
102
        return self._tdl_noise_c.dimensions
103
104
    @property
105
    def dimentions(self): # deprecated
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
106
        return self.dimensions
107
108
    @property
109
    def algorithm(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
110
        return self.noise_c.noise_type
111
    @algorithm.setter
112
    def algorithm(self, value):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
113
        lib.TCOD_noise_set_type(self.noise_c, value)
114
115
    @property
116
    def implementation(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
117
        return self._tdl_noise_c.implementation
118
    @implementation.setter
119
    def implementation(self, value):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
120
        if not 0 <= value < 3:
121
            raise ValueError('%r is not a valid implementation. ' % (value,))
122
        self._tdl_noise_c.implementation = value
123
124
    @property
125
    def hurst(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
126
        return self.noise_c.H
127
128
    @property
129
    def lacunarity(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
130
        return self.noise_c.lacunarity
131
132
    @property
133
    def octaves(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
134
        return self._tdl_noise_c.octaves
135
    @octaves.setter
136
    def octaves(self, value):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
137
        self._tdl_noise_c.octaves = value
138
139
    def get_point(self, x=0, y=0, z=0, w=0):
140
        """Return the noise value at the (x, y, z, w) point.
141
142
        Args:
143
            x (float): The position on the 1st axis.
144
            y (float): The position on the 2nd axis.
145
            z (float): The position on the 3rd axis.
146
            w (float): The position on the 4th axis.
147
        """
148
        return lib.NoiseGetSample(self._tdl_noise_c, (x, y, z, w))
149
150
    def sample_mgrid(self, mgrid):
151
        """Sample a mesh-grid array and return the result.
152
153
        The :any:`sample_ogrid` method performs better as there is a lot of
154
        overhead when working with large mesh-grids.
155
156
        Args:
157
            mgrid (numpy.ndarray): A mesh-grid array of points to sample.
158
                A contiguous array of type `numpy.float32` is preferred.
159
160
        Returns:
161
            numpy.ndarray: An array of sampled points.
162
163
                This array has the shape: ``mgrid.shape[:-1]``.
164
                The ``dtype`` is `numpy.float32`.
165
166
        .. versionadded:: 2.2
167
        """
168
        mgrid = np.ascontiguousarray(mgrid, np.float32)
169
        if mgrid.shape[0] != self.dimensions:
170
            raise ValueError('mgrid.shape[0] must equal self.dimensions, '
171
                             '%r[0] != %r' % (mgrid.shape, self.dimensions))
172
        out = np.ndarray(mgrid.shape[1:], np.float32)
173
        if mgrid.shape[1:] != out.shape:
174
            raise ValueError('mgrid.shape[1:] must equal out.shape, '
175
                             '%r[1:] != %r' % (mgrid.shape, out.shape))
176
        lib.NoiseSampleMeshGrid(self._tdl_noise_c, out.size,
177
                                ffi.cast('float*', mgrid.ctypes.data),
178
                                ffi.cast('float*', out.ctypes.data))
179
        return out
180
181
    def sample_ogrid(self, ogrid):
182
        """Sample an open mesh-grid array and return the result.
183
184
        Args
185
            ogrid (Sequence[Sequence[float]]): An open mesh-grid.
186
187
        Returns:
188
            numpy.ndarray: An array of sampled points.
189
190
                The ``shape`` is based on the lengths of the open mesh-grid
191
                arrays.
192
                The ``dtype`` is `numpy.float32`.
193
194
        .. versionadded:: 2.2
195
        """
196
        if len(ogrid) != self.dimensions:
197
            raise ValueError('len(ogrid) must equal self.dimensions, '
198
                             '%r != %r' % (len(ogrid), self.dimensions))
199
        ogrids = [np.ascontiguousarray(array, np.float32) for array in ogrid]
200
        out = np.ndarray([array.size for array in ogrids], np.float32)
201
        lib.NoiseSampleOpenMeshGrid(
202
            self._tdl_noise_c,
203
            len(ogrids),
204
            out.shape,
205
            [ffi.cast('float*', array.ctypes.data) for array in ogrids],
206
            ffi.cast('float*', out.ctypes.data),
207
            )
208
        return out
209
210
    def __getstate__(self):
211
        state = self.__dict__.copy()
212
        if self.dimensions < 4 and self.noise_c.waveletTileData == ffi.NULL:
213
            # Trigger a side effect of wavelet, so that copies will be synced.
214
            saved_algo = self.algorithm
215
            self.algorithm = tcod.libtcod.NOISE_WAVELET
0 ignored issues
show
Bug introduced by
The Module tcod.libtcod does not seem to have a member named NOISE_WAVELET.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
216
            self.get_point()
217
            self.algorithm = saved_algo
218
219
        waveletTileData = None
220
        if self.noise_c.waveletTileData != ffi.NULL:
221
            waveletTileData = list(self.noise_c.waveletTileData[0:32*32*32])
222
            state['_waveletTileData'] = waveletTileData
223
224
        state['noise_c'] = {
225
            'ndim': self.noise_c.ndim,
226
            'map': list(self.noise_c.map),
227
            'buffer': [list(sub_buffer) for sub_buffer in self.noise_c.buffer],
228
            'H': self.noise_c.H,
229
            'lacunarity': self.noise_c.lacunarity,
230
            'exponent': list(self.noise_c.exponent),
231
            'waveletTileData': waveletTileData,
232
            'noise_type': self.noise_c.noise_type,
233
            }
234
        state['_tdl_noise_c'] = {
235
            'dimensions': self._tdl_noise_c.dimensions,
236
            'implementation': self._tdl_noise_c.implementation,
237
            'octaves': self._tdl_noise_c.octaves,
238
            }
239
        return state
240
241
    def __setstate__(self, state):
242
        if isinstance(state, tuple): # deprecated format
243
            return self._setstate_old(state)
244
        # unpack wavelet tile data if it exists
245
        if '_waveletTileData' in state:
246
            state['_waveletTileData'] = ffi.new('float[]',
247
                                                state['_waveletTileData'])
248
            state['noise_c']['waveletTileData'] = state['_waveletTileData']
249
        else:
250
            state['noise_c']['waveletTileData'] = ffi.NULL
251
252
        # unpack perlin_data_t and link to Random instance
253
        state['noise_c']['rand'] = state['_random'].random_c
254
        state['noise_c'] = ffi.new('perlin_data_t*', state['noise_c'])
255
256
        # unpack TDLNoise and link to libtcod noise
257
        state['_tdl_noise_c']['noise'] = state['noise_c']
258
        state['_tdl_noise_c'] = ffi.new('TDLNoise*', state['_tdl_noise_c'])
259
        self.__dict__.update(state)
260
261
    def _setstate_old(self, state):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
262
        self._random = state[0]
263
        self.noise_c = ffi.new('perlin_data_t*')
264
        self.noise_c.ndim = state[3]
265
        ffi.buffer(self.noise_c.map)[:] = state[4]
266
        ffi.buffer(self.noise_c.buffer)[:] = state[5]
267
        self.noise_c.H = state[6]
268
        self.noise_c.lacunarity = state[7]
269
        ffi.buffer(self.noise_c.exponent)[:] = state[8]
270
        if state[9]:
271
            # high change of this being prematurely garbage collected!
272
            self.__waveletTileData = ffi.new('float[]', 32*32*32)
0 ignored issues
show
Coding Style introduced by
The attribute __waveletTileData was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
273
            ffi.buffer(self.__waveletTileData)[:] = state[9]
274
        self.noise_c.noise_type = state[10]
275
        self._tdl_noise_c = ffi.new('TDLNoise*',
276
                                    (self.noise_c, self.noise_c.ndim,
277
                                     state[1], state[2]))
278