Python вопросы

Список разделов Blender 3D Плагины

Описание: Обсуждение расширений для Blender
Модератор: exooman

Сообщение #81 grayich » 25.10.2019, 14:40

mac7 писал(а):вот и юзай аддоны потом
в том то и дело, что аддоном такое не сделать, вот и нужно использовать отдельную програмку, но Pavel похоже не нашёл подходящей(хотя должны быть) и пилит свою.
Linux
grayich M
Аватара
Откуда: Харьков
Сообщения: 5743

Сообщение #82 Pavel » 25.10.2019, 15:05

grayich писал(а):похоже не нашёл подходящей(хотя должны быть)
да, не нашёл подходящей. Все программы игнорировали клавиши на нумпаде. Вместо Num 1 писали просто 1. И я уже забросил написание своего скрипта. И я не хочу использовать аддоны, потому что они игнорируют клавиши (в зависимости от режима работы, когда активны определённые инструменты).

По поводу ассоциации файлов:
У меня получилось вручную ассоциировать файлы со своим скриптом. Вопрос:
как это сделать программно? Чтобы пользователь запустил программу, нажал кнопку и файлы ассоциировались.
Я пока сделал так:
Код: Выделить всё
import winreg, os, sys


subkey = 'Applications\\thm_editor.py\\shell\\open\\command'
hkey = winreg.CreateKeyEx(winreg.HKEY_CLASSES_ROOT, subkey, 0, winreg.KEY_WOW64_64KEY | winreg.KEY_ALL_ACCESS)
if hkey:
    thm_editor_path = os.path.abspath(__file__)
    python_exe_path = sys.executable
    command = '{0} "{1}" %1 %*'.format(python_exe_path, thm_editor_path)
    winreg.SetValue(winreg.HKEY_CLASSES_ROOT, subkey, winreg.REG_SZ, command)
    hkey.Close()
input('OK')

Но проблема в том, что это сработает только тогда, когда скрипт запущен батником от имени администратора:
Код: Выделить всё
python "E:\reg_test.py"
pause
Pavel M
Аватара
Сообщения: 1209

Сообщение #83 andreymal » 25.10.2019, 15:41

Можно собрать полноценный установщик setup.exe с помощью какого-нибудь NSIS, который сам сделает всё что надо. Но это целое отдельное приключение с кучей трудностей
Читая эту подпись, вы впустую потратили 5 секунд своей жизни.
andreymal M
Аватара
Сообщения: 1195

Сообщение #84 mac7 » 25.10.2019, 15:50

запись в HKEY_CLASSES_ROOT только по админ правам, но можно записать в HKEY_CURRENT_USER
https://superuser.com/questions/1064301/batch-fil ... s-without-administrator-rights

Добавлено спустя 2 минуты 37 секунд:
но не подходит для Windows 10 :(
mac7 M
Аватара
Откуда: Луцьк
Сообщения: 338

Сообщение #85 Pavel » 05.11.2019, 19:16

Как на питоне преобразовать вектор направления в углы Эйлера?

Просто я делаю импорт одного формата. Этот формат файлов создаётся редактором уровней. В общем в редакторе уровней я ставлю источник света, у которого есть параметры вращения в углах Эйлера. Когда я делаю компиляцию уровня, значения поворота преобразовываются в вектор направления и сохраняются в файл, который я потом импортирую в блендер.

Если в редакторе уровней у источника света будет такой поворот: (12.3, 45.6, 78.9), то после компиляции в файл сохранится такое значение направления этого источника света:
(-0.6980723738670349, 0.2130303829908371, 0.6836029887199402)

Как преобразовать это направление в привычные для блендера углы Эйлера?
Pavel M
Аватара
Сообщения: 1209

Сообщение #86 mac7 » 05.11.2019, 21:22

Pavel, ты точно ничего не напутал, этот угол не сходятся с этим вектором направления?
угол 2d вектора = arctg(y / x) результат будет в радианах по этому еще *180/pi,
думаю ты поймешь как найти углы для 3d вектора

Добавлено спустя 8 минут 42 секунды:
вроде результат будет в пределах -180 - 180
если надо 0 - 360
нужно результат провести через условие
if угол < 0:
угол += 360
mac7 M
Аватара
Откуда: Луцьк
Сообщения: 338

Сообщение #87 Pavel » 05.11.2019, 21:58

mac7 писал(а):ты точно ничего не напутал
а, забыл что система координат в редакторе уровней отличается от блендеровской. Нужно поменять местами вторую и третью координату. Направление будет таким:
Код: Выделить всё
-0.6980723738670349, 0.6836029887199402, 0.2130303829908371

mac7 писал(а):думаю ты поймешь как найти углы для 3d вектора
скорее нет. Там ведь нужно будет вычислять углы прямоугольных треугольников, которые являются проекциями на координатные плоскости XY, YZ, XZ? Или нет?

Я пока геометрически пытаюсь решить задачу. Не получается найти угол Z (должен быть равен 78.9):
Изображение
Pavel M
Аватара
Сообщения: 1209

  • 1

Сообщение #88 Bibo » 05.11.2019, 23:42

mathutils.Vector.to_track_quat
Как я понимаю, работает по принципу ограничителя "Track To" возвращая кватернион соответствующего поворота. Остается преобразовать полученный кватернион в углы эйлера.
Bibo
Аватара
Сообщения: 596

Сообщение #89 Pavel » 06.11.2019, 00:04

Bibo писал(а):mathutils.Vector.to_track_quat
о, сработало. Правда значение по оси Y теряется. Как я понимаю, не хватает информации для восстановления Y. Одного вектора направления не достаточно, чтобы восстановить все компоненты поворота.

А как можно сделать обратное действие? То есть перевести углы Эйлера в вектор направления. Просто мне теперь нужно сделать экспорт этих значений. Импорт вроде бы готов.
Pavel M
Аватара
Сообщения: 1209

  • 1

Сообщение #90 Bibo » 06.11.2019, 10:49

Pavel писал(а):То есть перевести углы Эйлера в вектор направления.
Преобразовать углы в матрицу поворота 3х3 (метод to_3x3). Каждый столбец полученной матрицы будет соответствовать локальным осям объекта. Обычно, объекты смотрят вдоль одной из своих локальных осей (или в противоположном направлении), следовательно, направляющему вектору будет соответствовать один из столбцов полученной матрицы (возможно в противоположном направлении). Например, камера в блендере смотрит в отрицательном направлении своей локальной оси Z, следовательно, вектор направления камеры соответствует противоположному направлению третьего столбца ее матрицы поворота.
Bibo
Аватара
Сообщения: 596

  • 1

Сообщение #91 Pavel » 06.11.2019, 11:25

Bibo, всё получилось :oD Минус одна головная боль. А то я скрипты импорта/экспорта почти доделал, хотел уже зарелизить, а тут заметил, что вращение у источников света другое.
Pavel M
Аватара
Сообщения: 1209

Сообщение #92 mac7 » 06.11.2019, 11:58

x = atan(0.2130303829908371 / sqrt(((-0.69807237386703490)^2) + (0.6836029887199402^2))) * (180 / pi) =
12.2999996
z= atan(-0.69807237386703490/-(0.6836029887199402))*180/pi=45.5999994
и обратно
x= -(sin(45.5999994*(pi/180))*cos(12.2999996*(pi/180)))=-0.69807236359
y = cos(45.5999994*(pi/180))*cos(12.2999996*(pi/180))=0.68360297879
z = sin(12.2999996*(pi/180))=0.21303037945
все довольно просто, но не спрашивай почему так :-D
mac7 M
Аватара
Откуда: Луцьк
Сообщения: 338

Сообщение #93 Pavel » 29.05.2020, 00:13

У меня такой вопрос по питону:
как создать как бы "конструктор" функций? У меня есть код, который выполняется много раз. И этот код критичен к производительности. Не могу даже добавить операторы if. Они сильно замедляют работу аддона. В общем мне нужно как бы сделать конструктор функций на лету. В зависимости от условий я выполняю те или интые участки кода функции. В общем вот код если не понятно объяснил:

Вот медленный вариант кода:
Код: Выделить всё
import struct

VERSION_1 = 1
VERSION_2 = 2

def read_file(version, data):
    p = 0
    # количество вершин (может быть несколько миллионов)
    vertices_count = struct.unpack('I', data[p : p + 4])
    p += 4
    for vertex_index in range(vertices_count):
        vertex_position = struct.unpack('3f', data[p : p + 12])
        p += 12
        # в каждой итерации цикла выполняется проверка этого условия,
        # что замедляет функцию
        if version == VERSION_2:
            vertex_normal = struct.unpack('3f', data[p : p + 12])
            p += 12

# здесь должен быть код, который читает файл и
# записывает его данные в переменную data
...

read_file(2, data)

А вот быстрый:

Код: Выделить всё
import struct


def read_file_v1(data):
    p = 0
    # количество вершин (может быть несколько миллионов)
    vertices_count = struct.unpack('I', data[p : p + 4])
    p += 4
    for vertex_index in range(vertices_count):
        vertex_position = struct.unpack('3f', data[p : p + 12])
        p += 12


def read_file_v2(data):
    p = 0
    # количество вершин (может быть несколько миллионов)
    vertices_count = struct.unpack('I', data[p : p + 4])
    p += 4
    for vertex_index in range(vertices_count):
        vertex_position = struct.unpack('3f', data[p : p + 12])
        p += 12
        vertex_normal = struct.unpack('3f', data[p : p + 12])
        p += 12


# здесь должен быть код, который читает файл и
# записывает его данные в переменную data
...

version = 2

if version == 1:
    read_file_v1(data)
elif version == 2:
    read_file_v2(data)

Во втором случае я создал две функции, которые немного отличаются. В моём аддоне их больше, чем две. Их уже расплодилось с десяток и трудно контролировать их.

Нужно избавиться от оператора if (смотреть первый вариант кода), но не создавать при этом много функций. Сделать как бы отдельные куски функций и склеить их на лету и выполнить эту сгенерированную функцию. Я знаю про существование exec. Но не хочеться его использовать. Это не правильно как-то. Может есть более правильный способ?
Pavel M
Аватара
Сообщения: 1209

Сообщение #94 Korchy » 29.05.2020, 10:39

В питоне внутри функций можно определять новые функции. Может такой механизм поможет.
Korchy M В сети
Аватара
Сообщения: 2951



Сообщение #95 Pavel » 29.05.2020, 12:53

Korchy, ну а вызов функции будет ведь занимать какое-то время. Я хотел сделать одну функцию, без создания лишних вызовов.
Pavel M
Аватара
Сообщения: 1209

Сообщение #96 mac7 » 29.05.2020, 21:25

Pavel, сделать эту часть С++
mac7 M
Аватара
Откуда: Луцьк
Сообщения: 338

Сообщение #97 Pavel » 29.05.2020, 21:58

mac7, я си++ не знаю. И мне желательно в аддоне не использовать компилируемый код, так как теряется возможность тестировать аддон у тех, кто не умеет компилировать. Пользователи вынуждены будут ждать, пока кто-то скомпилирует аддон для них.

Я всё таки переписал код на exec, так как другого варианта не вижу.
Pavel M
Аватара
Сообщения: 1209

  • 1

Сообщение #98 Pavel » 12.06.2020, 18:20

Как определить на что тратит больше всего времени код? Например, у меня есть импортёр, который состоит из большого количества строк. Мне нужно узнать время, которое тратит аддон для выполнения каждой строки. Хочу улучшить скорость работы импорта, но не знаю, какой код нужно оптимизировать и из-за чего вообще всё медленно работает.

Желательно иметь внешние инструменты. Например, для показа покрытия кода тестами, используется внешний пакет coverage. Так вот если его использовать, то не нужно модифицировать исходный тестируемый код.

В общем мне нужно узнать, сколько времени занимает выполнение каждой строки, без изменения этого кода. Вставлять много time.time() не вариант.

Добавлено спустя 59 минут 58 секунд:
Всё таки нашёл решение. Нужно установить pip install pprofile
Далее в коде прописать:
Код: Выделить всё
import pprofile
profiler = pprofile.Profile()
with profiler:
    # выполняемый код
    ...
profiler.print_stats()
profiler.dump_stats("D:\\profiler_stats.txt")

Создаётся такая статистика для каждой строки:
Код: Выделить всё
Line #|      Hits|         Time| Time per hit|      %|Source code
------+----------+-------------+-------------+-------+-----------
     1|         0|            0|            0|  0.00%|import bpy, mathutils
     2|         0|            0|            0|  0.00%|
     3|         0|            0|            0|  0.00%|from . import fmt, imp
     4|         0|            0|            0|  0.00%|from .. import xray_io, utils, version_utils
Pavel M
Аватара
Сообщения: 1209

Сообщение #99 Pavel » 28.11.2020, 18:11

Как написать конструктор функций?

Есть такой код:
Код: Выделить всё
import time


def funct_1(use_0, use_1, use_2, use_3, use_4, use_5, use_6, use_7, use_8, use_9):
    list_1 = []
    list_2 = []
    list_3 = []
    for i in range(10**6):
        coeff = 1
        if use_0:
            coeff += 0
        if use_1:
            coeff += 1
        if use_1:
            coeff += 1
        if use_2:
            coeff += 2
        if use_3:
            coeff += 3
        if use_4:
            coeff += 4
        if use_5:
            coeff += 5
        if use_6:
            coeff += 6
        if use_7:
            coeff += 7
        if use_8:
            coeff += 8
        if use_9:
            coeff += 9
        result_1 = i / coeff
        result_2 = i % coeff
        result_3 = i * 2 / coeff
        list_1.append(result_1)
        list_2.append(result_2)
        list_3.append(result_3)
    list_1.clear()
    list_2.clear()
    list_3.clear()


def funct_2():
    list_1 = []
    list_2 = []
    list_3 = []
    coeff = 1
    coeff += 0
    coeff += 1
    coeff += 1
    coeff += 2
    coeff += 3
    coeff += 4
    coeff += 5
    coeff += 6
    coeff += 7
    coeff += 8
    coeff += 9
    for i in range(10**6):
        result_1 = i / coeff
        result_2 = i % coeff
        result_3 = i * 2 / coeff
        list_1.append(result_1)
        list_2.append(result_2)
        list_3.append(result_3)
    list_1.clear()
    list_2.clear()
    list_3.clear()


count = 30

start_time = time.time()
for i in range(count):
    funct_1(True, True, True, True, True, True, True, True, True, True)
end_time = time.time()
time_1 = end_time - start_time
print('funct_1 time: {:.4f} seconds'.format(time_1))

start_time = time.time()
for i in range(count):
    funct_2()
end_time = time.time()
time_2 = end_time - start_time
print('funct_2 time: {:.4f} seconds'.format(time_2))

print('{:.2f} %'.format((time_1 - time_2) / time_1 * 100))
input('OK!')


Мне нужно избавиться от большого количества if конструкций в funct_1. Заранее неизвестно, какие параметры будут у функции. Мне нужно один раз вычислить все условия, а потом без if конструкций выполнить действия. Итераций цикла может быть десятки, а то и сотни миллионов. И действия в условиях не такие простые, как в этом синтетическом примере. Пример лишь показал суть проблемы. В реальном коде всё ещё более критично.

Единственное, что мне пришло в голову, это хранить весь код в строках, потом склеивать их и запустить с помощью exec. Но это костыль. Нет подсветки синтаксиса из-за того, что весь код будет хранится в строках.

Мне нужно один раз склеить код и запустить его как одну функцию. Эти if конструкции могут замедлить код в два раза. Для всех элементов последовательности условия должны быть одинаковыми. Поэтому эти условия нужно обработать только один раз, а не на каждой итерации цикла.

Как всё это сделать?
Pavel M
Аватара
Сообщения: 1209

Сообщение #100 grayich » 28.11.2020, 18:24

Pavel, нужно конкретику разбирать, что за параметры, зочем их мучать миллионы раз и т.п.
синтетика она и в африке синтетика, может тебе просто аналог case нужен, хз
Linux
grayich M
Аватара
Откуда: Харьков
Сообщения: 5743

Пред.След.

Вернуться в Плагины