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
|
# -*- coding: utf-8 -*-
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
from functools import lru_cache
import numpy as np
class DashAtlas(object):
""" """
def __init__(self, shape=(64, 1024, 4)):
# 512 patterns at max
self._data = np.zeros(shape, dtype=np.float32)
self._index = 0
self._atlas = {}
self['solid'] = (1e20, 0), (1, 1)
self['densely dotted'] = (0, 1), (1, 1)
self['dotted'] = (0, 2), (1, 1)
self['loosely dotted'] = (0, 3), (1, 1)
self['densely dashed'] = (1, 1), (1, 1)
self['dashed'] = (1, 2), (1, 1)
self['loosely dashed'] = (1, 4), (1, 1)
self['densely dashdotted'] = (1, 1, 0, 1), (1, 1, 1, 1)
self['dashdotted'] = (1, 2, 0, 2), (1, 1, 1, 1)
self['loosely dashdotted'] = (1, 3, 0, 3), (1, 1, 1, 1)
self['densely dashdotdotted'] = (1, 1, 0, 1, 0, 1), (1, 1, 1, 1)
self['dashdotdotted'] = (1, 2, 0, 2, 0, 2), (1, 1, 1, 1, 1, 1)
self['loosely dashdotdotted'] = (1, 3, 0, 3, 0, 3), (1, 1, 1, 1)
self._dirty = True
def __getitem__(self, key):
return self._atlas[key]
def __setitem__(self, key, value):
data, period = self.make_pattern(value[0], value[1])
self._data[self._index] = data
self._atlas[key] = [self._index / float(self._data.shape[0]), period]
self._index += 1
self._dirty = True
def make_pattern(self, pattern, caps=(1, 1)):
length = self._data.shape[1]
return _make_pattern(length, pattern, caps)
@lru_cache(maxsize=32)
def _make_pattern(length, pattern, caps):
"""Make a concrete dash pattern of a given length."""
# A pattern is defined as on/off sequence of segments
# It must be a multiple of 2
if len(pattern) > 1 and len(pattern) % 2:
pattern = [pattern[0] + pattern[-1]] + pattern[1:-1]
P = np.array(pattern)
# Period is the sum of all segment length
period = np.cumsum(P)[-1]
# Find all start and end of on-segment only
C, c = [], 0
for i in range(0, len(P) + 2, 2):
a = max(0.0001, P[i % len(P)])
b = max(0.0001, P[(i + 1) % len(P)])
C.extend([c, c + a])
c += a + b
C = np.array(C)
# Build pattern
Z = np.zeros((length, 4), dtype=np.float32)
for i in np.arange(0, len(Z)):
x = period * (i) / float(len(Z) - 1)
index = np.argmin(abs(C - (x)))
if index % 2 == 0:
if x <= C[index]:
dash_type = +1
else:
dash_type = 0
dash_start, dash_end = C[index], C[index + 1]
else:
if x > C[index]:
dash_type = -1
else:
dash_type = 0
dash_start, dash_end = C[index - 1], C[index]
Z[i] = C[index], dash_type, dash_start, dash_end
return Z, period
|