File size: 5,815 Bytes
53aafe9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51b769e
 
53aafe9
 
51b769e
53aafe9
 
 
 
 
 
 
 
 
51b769e
53aafe9
 
 
 
51b769e
53aafe9
51b769e
2b2ad8f
6f8f93d
 
 
 
 
 
51b769e
53aafe9
 
 
 
51b769e
 
 
 
 
a35ccd1
53aafe9
 
 
51b769e
53aafe9
 
 
 
 
6f8f93d
51b769e
2b2ad8f
51b769e
 
53aafe9
 
 
6f8f93d
 
 
53aafe9
2b2ad8f
51b769e
 
 
53aafe9
 
51b769e
 
1883218
51b769e
53aafe9
09c24d3
 
51b769e
6f8f93d
51b769e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1883218
51b769e
53aafe9
09c24d3
 
53aafe9
a35ccd1
 
53aafe9
a35ccd1
51b769e
53aafe9
6f8f93d
53aafe9
 
 
 
 
 
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
import math
import re
from flask import Flask, render_template, request
from PIL import Image, ImageOps

app = Flask(__name__)

def prepare_svg_symbol(file_storage):
    try:
        raw_data = file_storage.read().decode('utf-8')
        vb_match = re.search(r'viewBox=["\']([^"\']+)["\']', raw_data, re.I)
        vbox = vb_match.group(1) if vb_match else "0 0 100 100"
        
        inner = re.sub(r'<svg[^>]*>', '', raw_data, flags=re.I)
        inner = re.sub(r'</svg>', '', inner, flags=re.I)
        inner = re.sub(r'<\?xml[^>]*\?>|<!DOCTYPE[^>]*>', '', inner, flags=re.I)
        
        if 'fill=' not in inner:
            inner = f'<g fill="black">{inner}</g>'
        return inner, vbox
    except:
        return '<rect width="100" height="100" fill="black"/>', "0 0 100 100"

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/generate', methods=['POST'])
def generate():
    try:
        # --- Считываем параметры ---
        density = int(request.form.get('density', 40))
        gap_x = float(request.form.get('gap_x', 0))
        gap_y = float(request.form.get('gap_y', 0))
        shift_stagger = float(request.form.get('shift_stagger', 0))
        base_scale = float(request.form.get('base_scale', 1.0))
        growth = float(request.form.get('growth', 0)) 
        growth_type = request.form.get('growth_type', 'sine')
        invert_mode = request.form.get('invert') == 'true'
        
        # --- Параметры холста ---
        canvas_w = 1400
        canvas_h = 900
        step = canvas_w / density
        rows = math.ceil(canvas_h / step)

        # --- Подготовка шейпа ---
        svg_file = request.files.get('shape_svg')
        if svg_file and svg_file.filename != '':
            symbol_content, v_box = prepare_svg_symbol(svg_file)
        else:
            symbol_content, v_box = ('<rect width="100" height="100" fill="black"/>', "0 0 100 100")

        if request.form.get('current_svg_symbol'):
             symbol_content = request.form.get('current_svg_symbol')
             v_box = request.form.get('current_vbox', "0 0 100 100")

        vb_parts = [float(x) for x in v_box.split()]
        vb_w, vb_h = vb_parts[2], vb_parts[3]

        # --- Обработка Растрового Изображения (МАСКА) ---
        raster_file = request.files.get('raster_image')
        pixel_map = None
        if raster_file and raster_file.filename != '':
            try:
                img = Image.open(raster_file)
                img = ImageOps.fit(img, (canvas_w, canvas_h), method=Image.Resampling.LANCZOS)
                img = ImageOps.grayscale(img)
                pixel_map = img.load()
            except:
                pass

        # --- Генерация SVG ---
        body = []
        cell_w_max = step * (1.0 - gap_x)
        cell_h_max = step * (1.0 - gap_y)

        for r in range(rows):
            row_shift = (r * shift_stagger * step)
            
            for c in range(-density, density * 2):
                grid_x = c * step + row_shift
                grid_y = r * step
                
                if grid_x < -step or grid_x > canvas_w:
                    continue
                
                # 1. ПРОВЕРКА ПО КАРТИНКЕ (ВИДИМОСТЬ)
                if pixel_map:
                    sample_x = max(0, min(int(grid_x + step/2), canvas_w - 1))
                    sample_y = max(0, min(int(grid_y + step/2), canvas_h - 1))
                    brightness = pixel_map[sample_x, sample_y] / 255.0
                    
                    # Порог видимости: если яркость выше 0.5 — считаем это светом
                    is_visible = brightness > 0.5 if invert_mode else brightness < 0.5
                    if not is_visible:
                        continue

                # 2. ВЫЧИСЛЕНИЕ ШИРИНЫ ПО МАТЕМАТИЧЕСКОМУ АЛГОРИТМУ
                wave_norm = 0
                if growth_type == 'sine':
                    # Диагональная волна
                    wave_norm = (math.sin(c * 0.3 + r * 0.3) + 1) / 2 
                elif growth_type == 'linear':
                    # Слева направо
                    wave_norm = (c % density) / density
                elif growth_type == 'steps':
                    # Ступеньки
                    wave_norm = (r % 5) / 5.0
                
                # Модификатор ширины: чем больше growth, тем сильнее сужается объект
                # При growth = 0 ширина всегда 1.0 (максимум)
                mod_w = 1.0 - (wave_norm * growth)
                mod_w = max(0.01, min(1.0, mod_w))

                # Итоговые размеры
                content_w = cell_w_max * base_scale * mod_w
                content_h = cell_h_max * base_scale

                cx = grid_x + step / 2
                cy = grid_y + step / 2
                
                scale_x = content_w / vb_w
                scale_y = content_h / vb_h
                
                transform = f'translate({cx:.2f} {cy:.2f}) scale({scale_x:.4f} {scale_y:.4f}) translate({-vb_w/2:.2f} {-vb_h/2:.2f})'
                body.append(f'<g transform="{transform}">{symbol_content}</g>')

        return f'<svg xmlns="http://www.w3.org/2000/svg" width="{canvas_w}" height="{canvas_h}" viewBox="0 0 {canvas_w} {canvas_h}" style="background:white;">{"".join(body)}</svg>'

    except Exception as e:
        return f'<svg width="800" height="200"><text y="50" fill="red" font-size="20">Error: {str(e)}</text></svg>', 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=7860)