Sidebar > [ベクトル矢印ツール]", "description": "エラー修正版: テキストエディタ実行時でも自身のソースコードを取得して設定を保存できます。", "category": "Object", } # ============================================================================== # ★設定エリア (Global Configuration) # ============================================================================== PREFIX = "combined_vector_arrow" TAB_NAME = "[ベクトル矢印ツール]" # ▼ リンク設定リスト LINK_LIST = [ ("ドキュメント", "https://www.notion.so/20251110-2a6298fa488c8014ab50c3eaca269d90"), ] # ▼ パネル設定 ( "表示名", 1=開く / 0=閉じる ) # アルファベット順に整理 PANEL_CONFIGS = { "ARROW_PT_overlay_settings": ("A: Viewport オーバーレイ設定", 1), "ARROW_PT_p1": ("B: 単一ベクトル生成", 0"> Sidebar > [ベクトル矢印ツール]", "description": "エラー修正版: テキストエディタ実行時でも自身のソースコードを取得して設定を保存できます。", "category": "Object", } # ============================================================================== # ★設定エリア (Global Configuration) # ============================================================================== PREFIX = "combined_vector_arrow" TAB_NAME = "[ベクトル矢印ツール]" # ▼ リンク設定リスト LINK_LIST = [ ("ドキュメント", "https://www.notion.so/20251110-2a6298fa488c8014ab50c3eaca269d90"), ] # ▼ パネル設定 ( "表示名", 1=開く / 0=閉じる ) # アルファベット順に整理 PANEL_CONFIGS = { "ARROW_PT_overlay_settings": ("A: Viewport オーバーレイ設定", 1), "ARROW_PT_p1": ("B: 単一ベクトル生成", 0"> Sidebar > [ベクトル矢印ツール]", "description": "エラー修正版: テキストエディタ実行時でも自身のソースコードを取得して設定を保存できます。", "category": "Object", } # ============================================================================== # ★設定エリア (Global Configuration) # ============================================================================== PREFIX = "combined_vector_arrow" TAB_NAME = "[ベクトル矢印ツール]" # ▼ リンク設定リスト LINK_LIST = [ ("ドキュメント", "https://www.notion.so/20251110-2a6298fa488c8014ab50c3eaca269d90"), ] # ▼ パネル設定 ( "表示名", 1=開く / 0=閉じる ) # アルファベット順に整理 PANEL_CONFIGS = { "ARROW_PT_overlay_settings": ("A: Viewport オーバーレイ設定", 1), "ARROW_PT_p1": ("B: 単一ベクトル生成", 0">
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# アドオン基本情報
# ---------------------------------------------------------------------
bl_info = {
"name": "ベクトル矢印 複合演算ツール (自動保存・ABC順)",
"author": "Gemini & zionadchat",
"version": (7, 8, 1),
"blender": (4, 1, 0),
"location": "View3D > Sidebar > [ベクトル矢印ツール]",
"description": "エラー修正版: テキストエディタ実行時でも自身のソースコードを取得して設定を保存できます。",
"category": "Object",
}
# ==============================================================================
# ★設定エリア (Global Configuration)
# ==============================================================================
PREFIX = "combined_vector_arrow"
TAB_NAME = "[ベクトル矢印ツール]"
# ▼ リンク設定リスト
LINK_LIST = [
("ドキュメント", "<https://www.notion.so/20251110-2a6298fa488c8014ab50c3eaca269d90>"),
]
# ▼ パネル設定 ( "表示名", 1=開く / 0=閉じる )
# アルファベット順に整理
PANEL_CONFIGS = {
"ARROW_PT_overlay_settings": ("A: Viewport オーバーレイ設定", 1),
"ARROW_PT_p1": ("B: 単一ベクトル生成", 0),
"ARROW_PT_p2": ("C: 終点連結 (V1+V2)", 0),
"ARROW_PT_p3": ("D: ベクトル合算", 0),
"ARROW_PT_3axis": ("E: 3軸 (XYZ) 生成", 1),
"ARROW_PT_global_rot": ("F: グローバル回転", 0),
"ARROW_PT_generate_script": ("G: 設定の保存・出力", 1),
"ARROW_PT_links": ("H: リンク集", 0),
"ARROW_PT_admin": ("I: 管理", 0),
}
# =================================================================================
# ★★★★★ 設定ブロック (保存されるデフォルト値) ★★★★★
# =================================================================================
SETTINGS_BLOCK = """
# --- Defaults for Panel1Props ---
"arrow_shape_preset": "太め",
"start_x": 5.000,
"start_y": 10.000,
"start_z": 10.000,
"end_x": 0.000,
"end_y": 0.000,
"end_z": 0.000,
"shaft_radius": 0.250,
"cone_radius": 0.600,
"cone_height": 2.000,
"cone_only": False,
"shaft_color": (0.470, 0.004, 0.280, 1.000),
"cone_color": (0.106, 0.000, 1.000, 1.000),
"object_name": "VectorArrow",
"parent_collection_name": "矢印ベクトル",
# --- Defaults for Panel2Props ---
"arrow_shape_preset": "太め",
"v1_start_x": 0.000,
"v1_start_y": 10.000,
"v1_start_z": 10.000,
"v1_end_x": 0.000,
"v1_end_y": 0.000,
"v1_end_z": 0.000,
"v2_end_x": 0.000,
"v2_end_y": -10.000,
"v2_end_z": 0.000,
"shaft_radius": 0.250,
"cone_radius": 0.600,
"cone_height": 2.000,
"cone_only": False,
"v1_color": (0.046, 1.000, 0.006, 1.000),
"v2_color": (1.000, 0.982, 0.015, 1.000),
"v3_color": (0.229, 0.017, 1.000, 1.000),
# --- Defaults for Panel3Props ---
"arrow_shape_preset": "円柱",
"v1_start_x": 0.000,
"v1_start_y": 10.000,
"v1_start_z": 0.000,
"v1_end_x": 0.000,
"v1_end_y": 10.000,
"v1_end_z": 10.000,
"v2_start_x": 5.000,
"v2_start_y": 10.000,
"v2_start_z": 0.000,
"v2_end_x": 5.000,
"v2_end_y": 10.000,
"v2_end_z": 10.000,
"shaft_radius": 1.000,
"cone_radius": 0.001,
"cone_height": 0.010,
"cone_only": False,
"v1_color": (1.000, 1.000, 0.000, 1.000),
"v2_color": (0.007, 0.005, 1.000, 1.000),
"v3_color": (1.000, 0.000, 1.000, 1.000),
# --- Defaults for Panel3AxisProps ---
"arrow_shape_preset": "標準",
"origin_x": 0.000,
"origin_y": 0.000,
"origin_z": 0.000,
"axis_length": 10.000,
"shaft_radius": 0.100,
"cone_radius": 0.300,
"cone_height": 0.800,
"cone_only": False,
"x_color": (1.000, 0.000, 0.000, 1.000),
"y_color": (0.000, 1.000, 0.000, 1.000),
"z_color": (0.000, 0.000, 1.000, 1.000),
"parent_collection_name": "矢印ベクトル",
# --- Defaults for GlobalRotationProperties ---
"rotation_x": 0.000,
"rotation_y": 0.000,
"rotation_z": 0.000,
# --- ARROW_GEOMETRY_PRESETS ---
ARROW_GEOMETRY_PRESETS = {
"標準": { "shaft_radius": 0.1, "cone_radius": 0.4, "cone_height": 1.0 },
"細め": { "shaft_radius": 0.05, "cone_radius": 0.2, "cone_height": 0.8 },
"太め": { "shaft_radius": 0.25, "cone_radius": 0.6, "cone_height": 2.0 },
"鋭角": { "shaft_radius": 0.08, "cone_radius": 0.2, "cone_height": 2.5 },
"円柱": { "shaft_radius": 0.1, "cone_radius": 0.1, "cone_height": 0.01 },
}
"""
# =================================================================================
# ★★★★★ 設定ブロック (ここまで) ★★★★★
# =================================================================================
import bpy
import mathutils
import math
import webbrowser
import re
import ast
import inspect
import sys
import os
from mathutils import Matrix, Vector
from bpy.types import Operator, Panel, PropertyGroup
from bpy.props import StringProperty, FloatProperty, FloatVectorProperty, PointerProperty, EnumProperty, BoolProperty
# --- 設定解析 ---
def parse_settings_block(block_text):
settings = {}
current_section = None
presets_str = ""
in_presets = False
for line in block_text.strip().split('\n'):
line = line.strip()
if not line: continue
header_match = re.match(r'# --- Defaults for (\w+) ---', line)
if header_match:
current_section = header_match.group(1); settings[current_section] = {}; in_presets = False; continue
if 'ARROW_GEOMETRY_PRESETS' in line: in_presets = True; current_section = None
if in_presets: presets_str += line + '\n'; continue
if current_section and ':' in line:
try:
key, value = line.split(':', 1); key = ast.literal_eval(key); value = value.strip().rstrip(',')
settings[current_section][key] = ast.literal_eval(value)
except: pass
try:
ns = {}; exec(presets_str, ns); settings['ARROW_GEOMETRY_PRESETS'] = ns.get('ARROW_GEOMETRY_PRESETS', {})
except: settings['ARROW_GEOMETRY_PRESETS'] = {}
return settings
PARSED_SETTINGS = parse_settings_block(SETTINGS_BLOCK)
ARROW_GEOMETRY_PRESETS = PARSED_SETTINGS.get('ARROW_GEOMETRY_PRESETS', {})
def _get_default(section, key, fallback): return PARSED_SETTINGS.get(section, {}).get(key, fallback)
def _generate_preset_items(): return [(name, name, f"プリセット「{name}」を適用") for name in ARROW_GEOMETRY_PRESETS.keys()]
ARROW_PRESET_ITEMS = _generate_preset_items()
ADDON_ID_PREFIX = PREFIX
ADDON_CATEGORY_NAME = TAB_NAME
# ---------------------------------------------------------------------
# 共通関数
# ---------------------------------------------------------------------
def get_or_create_collection(collection_name, parent_collection=None):
if parent_collection is None: parent_collection = bpy.context.scene.collection
if collection_name in parent_collection.children: return parent_collection.children[collection_name]
new_collection = bpy.data.collections.new(collection_name)
parent_collection.children.link(new_collection)
return new_collection
def get_or_create_material(color, name_prefix="VecMat"):
mat_name = f"{name_prefix}_{color[0]:.2f}_{color[1]:.2f}_{color[2]:.2f}_{color[3]:.2f}"
if mat_name in bpy.data.materials: return bpy.data.materials[mat_name]
mat = bpy.data.materials.new(name=mat_name); mat.use_nodes = True
bsdf = mat.node_tree.nodes.get('Principled BSDF')
if bsdf: bsdf.inputs['Base Color'].default_value = color
return mat
def create_arrow_geometry(context, length, shaft_radius, cone_radius, cone_height, shaft_color, cone_color, cone_only=False):
bpy.ops.object.select_all(action='DESELECT')
if cone_only or length <= cone_height:
final_cone_height = length
final_cone_radius = cone_radius * (length / cone_height) if (cone_height > 1e-6 and not cone_only) else cone_radius
bpy.ops.mesh.primitive_cone_add(radius1=final_cone_radius, depth=final_cone_height, vertices=32, location=(0,0,0))
arrow_obj = context.active_object; arrow_obj.data.transform(Matrix.Translation((0,0,final_cone_height/2.0)))
arrow_obj.data.materials.append(get_or_create_material(cone_color, "ConeColor"))
return arrow_obj
verts = []; faces = []; num_v = 32; shaft_length = length - cone_height
verts.append(Vector((0,0,length)))
for i in range(num_v): a=(i/num_v)*2*math.pi; verts.append(Vector((cone_radius*math.cos(a), cone_radius*math.sin(a), shaft_length)))
for i in range(num_v): a=(i/num_v)*2*math.pi; verts.append(Vector((shaft_radius*math.cos(a), shaft_radius*math.sin(a), shaft_length)))
for i in range(num_v): a=(i/num_v)*2*math.pi; verts.append(Vector((shaft_radius*math.cos(a), shaft_radius*math.sin(a), 0)))
cone_f, shaft_f = [], []
for i in range(num_v):
i_n = (i+1)%num_v
faces.append((0, 1+i_n, 1+i)); cone_f.append(len(faces)-1)
faces.append((1+i, 1+i_n, 1+num_v+i_n, 1+num_v+i)); cone_f.append(len(faces)-1)
faces.append((1+num_v+i, 1+num_v+i_n, 1+2*num_v+i_n, 1+2*num_v+i)); shaft_f.append(len(faces)-1)
faces.append(tuple(reversed(range(1+2*num_v, 1+3*num_v)))); shaft_f.append(len(faces)-1)
mesh = bpy.data.meshes.new("ArrowMesh"); mesh.from_pydata(verts, [], faces)
obj = bpy.data.objects.new("ArrowObject", mesh)
obj.data.materials.append(get_or_create_material(cone_color, "ConeColor")); obj.data.materials.append(get_or_create_material(shaft_color, "ShaftColor"))
for idx in cone_f: obj.data.polygons[idx].material_index = 0
for idx in shaft_f: obj.data.polygons[idx].material_index = 1
mesh.update(); context.collection.objects.link(obj); context.view_layer.objects.active=obj; obj.select_set(True)
return obj
def create_single_arrow_from_points(context, name, start, end, sr, cr, ch, sc, cc, co=False):
direction = end - start; length = direction.length
if length < 1e-6: return None
obj = create_arrow_geometry(context, length, sr, cr, ch, sc, cc, co)
if obj:
obj.name = name; obj.location = start
if direction.length > 0: obj.rotation_mode='QUATERNION'; obj.rotation_quaternion = direction.normalized().to_track_quat('Z','Y')
return obj
def update_grid_scale(self, context):
if context.space_data and context.space_data.type == 'VIEW_3D': context.space_data.overlay.grid_scale = self.scale
def update_panel_geometry_from_preset(self, context):
if self.arrow_shape_preset in ARROW_GEOMETRY_PRESETS:
for k,v in ARROW_GEOMETRY_PRESETS[self.arrow_shape_preset].items():
if hasattr(self, k): setattr(self, k, v)
# ---------------------------------------------------------------------
# プロパティ
# ---------------------------------------------------------------------
class OverlaySettings(PropertyGroup):
scale: FloatProperty(name="スケール", default=10.0, min=0.001, update=update_grid_scale, precision=2)
class Panel1Props(PropertyGroup):
arrow_shape_preset: EnumProperty(name="形状プリセット", items=ARROW_PRESET_ITEMS, update=update_panel_geometry_from_preset, default=_get_default("Panel1Props", "arrow_shape_preset", "標準"))
start_x: FloatProperty(name="X", default=_get_default("Panel1Props", "start_x", 0.0), precision=2)
start_y: FloatProperty(name="Y", default=_get_default("Panel1Props", "start_y", 0.0), precision=2)
start_z: FloatProperty(name="Z", default=_get_default("Panel1Props", "start_z", 0.0), precision=2)
end_x: FloatProperty(name="X", default=_get_default("Panel1Props", "end_x", 5.0), precision=2)
end_y: FloatProperty(name="Y", default=_get_default("Panel1Props", "end_y", 0.0), precision=2)
end_z: FloatProperty(name="Z", default=_get_default("Panel1Props", "end_z", 18.52), precision=2)
shaft_radius: FloatProperty(name="シャフト半径", default=_get_default("Panel1Props", "shaft_radius", 0.05), precision=2)
cone_radius: FloatProperty(name="円錐半径", default=_get_default("Panel1Props", "cone_radius", 0.2), precision=2)
cone_height: FloatProperty(name="円錐高さ", default=_get_default("Panel1Props", "cone_height", 0.8), precision=2)
cone_only: BoolProperty(name="円錐のみ", default=_get_default("Panel1Props", "cone_only", False))
shaft_color: FloatVectorProperty(name="シャフト色", subtype='COLOR', size=4, default=_get_default("Panel1Props", "shaft_color", (0.2,0.8,1,1)))
cone_color: FloatVectorProperty(name="円錐色", subtype='COLOR', size=4, default=_get_default("Panel1Props", "cone_color", (0,0.4,0.8,1)))
object_name: StringProperty(name="オブジェクト名", default=_get_default("Panel1Props", "object_name", "VectorArrow"))
parent_collection_name: StringProperty(name="親コレクション名", default=_get_default("Panel1Props", "parent_collection_name", "矢印ベクトル"))
class Panel2Props(PropertyGroup):
arrow_shape_preset: EnumProperty(name="形状プリセット", items=ARROW_PRESET_ITEMS, update=update_panel_geometry_from_preset, default=_get_default("Panel2Props", "arrow_shape_preset", "標準"))
v1_start_x: FloatProperty(name="X", default=_get_default("Panel2Props", "v1_start_x", 0.0))
v1_start_y: FloatProperty(name="Y", default=_get_default("Panel2Props", "v1_start_y", 0.0))
v1_start_z: FloatProperty(name="Z", default=_get_default("Panel2Props", "v1_start_z", 0.0))
v1_end_x: FloatProperty(name="X", default=_get_default("Panel2Props", "v1_end_x", 5.0))
v1_end_y: FloatProperty(name="Y", default=_get_default("Panel2Props", "v1_end_y", 5.0))
v1_end_z: FloatProperty(name="Z", default=_get_default("Panel2Props", "v1_end_z", 0.0))
v2_end_x: FloatProperty(name="X", default=_get_default("Panel2Props", "v2_end_x", 10.0))
v2_end_y: FloatProperty(name="Y", default=_get_default("Panel2Props", "v2_end_y", 0.0))
v2_end_z: FloatProperty(name="Z", default=_get_default("Panel2Props", "v2_end_z", 0.0))
shaft_radius: FloatProperty(name="シャフト半径", default=_get_default("Panel2Props", "shaft_radius", 0.1))
cone_radius: FloatProperty(name="円錐半径", default=_get_default("Panel2Props", "cone_radius", 0.71))
cone_height: FloatProperty(name="円錐高さ", default=_get_default("Panel2Props", "cone_height", 1.0))
cone_only: BoolProperty(name="円錐のみ", default=_get_default("Panel2Props", "cone_only", False))
v1_color: FloatVectorProperty(name="V1色", subtype='COLOR', size=4, default=_get_default("Panel2Props", "v1_color", (0.2,1,0.9,1)))
v2_color: FloatVectorProperty(name="V2色", subtype='COLOR', size=4, default=_get_default("Panel2Props", "v2_color", (0,0,1,1)))
v3_color: FloatVectorProperty(name="V3色", subtype='COLOR', size=4, default=_get_default("Panel2Props", "v3_color", (1,0.8,0,1)))
class Panel3Props(PropertyGroup):
arrow_shape_preset: EnumProperty(name="形状プリセット", items=ARROW_PRESET_ITEMS, update=update_panel_geometry_from_preset, default=_get_default("Panel3Props", "arrow_shape_preset", "細め"))
v1_start_x: FloatProperty(name="X", default=_get_default("Panel3Props", "v1_start_x", 0.0))
v1_start_y: FloatProperty(name="Y", default=_get_default("Panel3Props", "v1_start_y", 10.0))
v1_start_z: FloatProperty(name="Z", default=_get_default("Panel3Props", "v1_start_z", 0.0))
v1_end_x: FloatProperty(name="X", default=_get_default("Panel3Props", "v1_end_x", 5.0))
v1_end_y: FloatProperty(name="Y", default=_get_default("Panel3Props", "v1_end_y", 10.0))
v1_end_z: FloatProperty(name="Z", default=_get_default("Panel3Props", "v1_end_z", 10.0))
v2_start_x: FloatProperty(name="X", default=_get_default("Panel3Props", "v2_start_x", 5.0))
v2_start_y: FloatProperty(name="Y", default=_get_default("Panel3Props", "v2_start_y", 10.0))
v2_start_z: FloatProperty(name="Z", default=_get_default("Panel3Props", "v2_start_z", 0.0))
v2_end_x: FloatProperty(name="X", default=_get_default("Panel3Props", "v2_end_x", 5.0))
v2_end_y: FloatProperty(name="Y", default=_get_default("Panel3Props", "v2_end_y", 10.0))
v2_end_z: FloatProperty(name="Z", default=_get_default("Panel3Props", "v2_end_z", 10.0))
shaft_radius: FloatProperty(name="シャフト半径", default=_get_default("Panel3Props", "shaft_radius", 0.84))
cone_radius: FloatProperty(name="円錐半径", default=_get_default("Panel3Props", "cone_radius", 0.2))
cone_height: FloatProperty(name="円錐高さ", default=_get_default("Panel3Props", "cone_height", 0.8))
cone_only: BoolProperty(name="円錐のみ", default=_get_default("Panel3Props", "cone_only", False))
v1_color: FloatVectorProperty(name="V1色", subtype='COLOR', size=4, default=_get_default("Panel3Props", "v1_color", (1,1,0,1)))
v2_color: FloatVectorProperty(name="V2色", subtype='COLOR', size=4, default=_get_default("Panel3Props", "v2_color", (0,1,1,1)))
v3_color: FloatVectorProperty(name="V3色", subtype='COLOR', size=4, default=_get_default("Panel3Props", "v3_color", (1,0,1,1)))
class Panel3AxisProps(PropertyGroup):
arrow_shape_preset: EnumProperty(name="形状プリセット", items=ARROW_PRESET_ITEMS, update=update_panel_geometry_from_preset, default=_get_default("Panel3AxisProps", "arrow_shape_preset", "標準"))
origin_x: FloatProperty(name="原点X", default=_get_default("Panel3AxisProps", "origin_x", 0.0))
origin_y: FloatProperty(name="原点Y", default=_get_default("Panel3AxisProps", "origin_y", 0.0))
origin_z: FloatProperty(name="原点Z", default=_get_default("Panel3AxisProps", "origin_z", 0.0))
axis_length: FloatProperty(name="各軸の長さ", default=_get_default("Panel3AxisProps", "axis_length", 5.0))
shaft_radius: FloatProperty(name="シャフト半径", default=_get_default("Panel3AxisProps", "shaft_radius", 0.1))
cone_radius: FloatProperty(name="円錐半径", default=_get_default("Panel3AxisProps", "cone_radius", 0.3))
cone_height: FloatProperty(name="円錐高さ", default=_get_default("Panel3AxisProps", "cone_height", 0.8))
cone_only: BoolProperty(name="円錐のみ", default=_get_default("Panel3AxisProps", "cone_only", False))
x_color: FloatVectorProperty(name="X軸 色", subtype='COLOR', size=4, default=_get_default("Panel3AxisProps", "x_color", (1,0,0,1)))
y_color: FloatVectorProperty(name="Y軸 色", subtype='COLOR', size=4, default=_get_default("Panel3AxisProps", "y_color", (0,1,0,1)))
z_color: FloatVectorProperty(name="Z軸 色", subtype='COLOR', size=4, default=_get_default("Panel3AxisProps", "z_color", (0,0,1,1)))
parent_collection_name: StringProperty(name="親コレクション名", default=_get_default("Panel3AxisProps", "parent_collection_name", "矢印ベクトル"))
class GlobalRotationProperties(PropertyGroup):
rotation_x: FloatProperty(name="X", default=_get_default("GlobalRotationProperties", "rotation_x", 0.0), subtype='ANGLE')
rotation_y: FloatProperty(name="Y", default=_get_default("GlobalRotationProperties", "rotation_y", 0.0), subtype='ANGLE')
rotation_z: FloatProperty(name="Z", default=_get_default("GlobalRotationProperties", "rotation_z", 0.0), subtype='ANGLE')
# ---------------------------------------------------------------------
# オペレーター
# ---------------------------------------------------------------------
class ARROW_OT_SetOverlayScale(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.set_overlay_scale"; bl_label = "Overlayスケール"; bl_options = {'REGISTER', 'UNDO'}
scale: FloatProperty()
def execute(self, context): context.scene.overlay_settings.scale = self.scale; return {'FINISHED'}
class ARROW_OT_CreatePanel1(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.create_p1"; bl_label = "生成"; bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
p = context.scene.adv_vector_arrow_props_p1
obj = create_single_arrow_from_points(context, p.object_name, Vector((p.start_x,p.start_y,p.start_z)), Vector((p.end_x,p.end_y,p.end_z)), p.shaft_radius, p.cone_radius, p.cone_height, p.shaft_color, p.cone_color, p.cone_only)
if not obj: self.report({'WARNING'}, "生成失敗: 長さが足りません"); return {'CANCELLED'}
col = get_or_create_collection(p.parent_collection_name); sub = get_or_create_collection(f"P1_{len(col.children):03d}_{p.object_name}", col)
for c in obj.users_collection: c.objects.unlink(obj)
sub.objects.link(obj); return {'FINISHED'}
class ARROW_OT_CreatePanel2(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.create_p2"; bl_label = "生成"; bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
p = context.scene.adv_vector_arrow_props_p2; p1 = context.scene.adv_vector_arrow_props_p1
v1s=Vector((p.v1_start_x,p.v1_start_y,p.v1_start_z)); v1e=Vector((p.v1_end_x,p.v1_end_y,p.v1_end_z)); v2e=Vector((p.v2_end_x,p.v2_end_y,p.v2_end_z))
sh={"sr":p.shaft_radius,"cr":p.cone_radius,"ch":p.cone_height,"co":p.cone_only}
objs = [
create_single_arrow_from_points(context,"V1",v1s,v1e,sh['sr'],sh['cr'],sh['ch'],p.v1_color,p.v1_color,sh['co']),
create_single_arrow_from_points(context,"V2",v1e,v2e,sh['sr'],sh['cr'],sh['ch'],p.v2_color,p.v2_color,sh['co']),
create_single_arrow_from_points(context,"V3_Sum",v1s,v2e,sh['sr'],sh['cr'],sh['ch'],p.v3_color,p.v3_color,sh['co'])
]
col = get_or_create_collection(p1.parent_collection_name); sub = get_or_create_collection(f"P2_{len(col.children):03d}_Chain", col)
for o in objs:
if o:
for c in o.users_collection: c.objects.unlink(o)
sub.objects.link(o)
return {'FINISHED'}
class ARROW_OT_CreatePanel3(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.create_p3"; bl_label = "生成"; bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
p = context.scene.adv_vector_arrow_props_p3; p1 = context.scene.adv_vector_arrow_props_p1
v1s=Vector((p.v1_start_x,p.v1_start_y,p.v1_start_z)); v1e=Vector((p.v1_end_x,p.v1_end_y,p.v1_end_z))
v2s=Vector((p.v2_start_x,p.v2_start_y,p.v2_start_z)); v2e=Vector((p.v2_end_x,p.v2_end_y,p.v2_end_z))
v3e = (v1e-v1s) + (v2e-v2s)
sh={"sr":p.shaft_radius,"cr":p.cone_radius,"ch":p.cone_height,"co":p.cone_only}
objs = [
create_single_arrow_from_points(context,"V1_Base",v1s,v1e,sh['sr'],sh['cr'],sh['ch'],p.v1_color,p.v1_color,sh['co']),
create_single_arrow_from_points(context,"V2_Base",v2s,v2e,sh['sr'],sh['cr'],sh['ch'],p.v2_color,p.v2_color,sh['co']),
create_single_arrow_from_points(context,"V3_Result",Vector((0,0,0)),v3e,sh['sr'],sh['cr'],sh['ch'],p.v3_color,p.v3_color,sh['co'])
]
col = get_or_create_collection(p1.parent_collection_name); sub = get_or_create_collection(f"P3_{len(col.children):03d}_Sum", col)
for o in objs:
if o:
for c in o.users_collection: c.objects.unlink(o)
sub.objects.link(o)
return {'FINISHED'}
class ARROW_OT_Create3Axis(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.create_3axis"; bl_label = "3軸(XYZ)生成"; bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
p = context.scene.adv_vector_arrow_props_3axis
org = Vector((p.origin_x,p.origin_y,p.origin_z)); L = p.axis_length
sh={"sr":p.shaft_radius,"cr":p.cone_radius,"ch":p.cone_height,"co":p.cone_only}
objs = [
create_single_arrow_from_points(context,"Axis_X",org,org+Vector((L,0,0)),sh['sr'],sh['cr'],sh['ch'],p.x_color,p.x_color,sh['co']),
create_single_arrow_from_points(context,"Axis_Y",org,org+Vector((0,L,0)),sh['sr'],sh['cr'],sh['ch'],p.y_color,p.y_color,sh['co']),
create_single_arrow_from_points(context,"Axis_Z",org,org+Vector((0,0,L)),sh['sr'],sh['cr'],sh['ch'],p.z_color,p.z_color,sh['co'])
]
col = get_or_create_collection(p.parent_collection_name); sub = get_or_create_collection(f"3Axis_{len(col.children):03d}_XYZ", col)
for o in objs:
if o:
for c in o.users_collection: c.objects.unlink(o)
sub.objects.link(o)
return {'FINISHED'}
class ARROW_OT_RotateGlobal(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.rotate_global"; bl_label = "適用"; bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
p = context.scene.adv_vector_arrow_props_global_rot
if not context.selected_objects: return {'CANCELLED'}
mat = Matrix.Translation(context.scene.cursor.location) @ Matrix.Rotation(p.rotation_z,4,'Z') @ Matrix.Rotation(-p.rotation_y,4,'Y') @ Matrix.Rotation(-p.rotation_x,4,'X') @ Matrix.Translation(-context.scene.cursor.location)
for o in context.selected_objects: o.matrix_world = mat @ o.matrix_world
return {'FINISHED'}
class ARROW_OT_ResetSingleProperty(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.reset_single_prop"; bl_label = ""; bl_options = {'REGISTER', 'UNDO'}
prop_group_name: StringProperty(); prop_name: StringProperty()
def execute(self, context):
p = getattr(context.scene, self.prop_group_name); rna = p.bl_rna.properties.get(self.prop_name)
if rna: setattr(p, self.prop_name, _get_default(p.bl_rna.name, self.prop_name, rna.default))
return {'FINISHED'}
class ARROW_OT_ResetPanelProperties(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.reset_panel_props"; bl_label = ""; bl_options = {'REGISTER', 'UNDO'}
panel_id: StringProperty()
def execute(self, context):
map = {"P1":"adv_vector_arrow_props_p1","P2":"adv_vector_arrow_props_p2","P3":"adv_vector_arrow_props_p3","3AXIS":"adv_vector_arrow_props_3axis","GLOBAL":"adv_vector_arrow_props_global_rot"}
if not map.get(self.panel_id): return {'CANCELLED'}
p = getattr(context.scene, map[self.panel_id]); sec = p.bl_rna.name
for k in p.__annotations__.keys():
if p.bl_rna.properties.get(k): setattr(p, k, _get_default(sec, k, p.bl_rna.properties[k].default))
return {'FINISHED'}
# ★★★ 修正されたスクリプト生成オペレーター ★★★
class ARROW_OT_GenerateScript(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.generate_script"; bl_label = "設定済みスクリプトをエディタに出力"
def execute(self, context):
def fmt(v):
if isinstance(v, str): return f'"{v}"'
if isinstance(v, (mathutils.Vector, bpy.types.bpy_prop_array)): return f'({", ".join(f"{x:.3f}" for x in v)})'
if isinstance(v, float): return f'{v:.3f}'
return repr(v)
scene = context.scene
props_map = {
"Panel1Props": scene.adv_vector_arrow_props_p1, "Panel2Props": scene.adv_vector_arrow_props_p2,
"Panel3Props": scene.adv_vector_arrow_props_p3, "Panel3AxisProps": scene.adv_vector_arrow_props_3axis,
"GlobalRotationProperties": scene.adv_vector_arrow_props_global_rot
}
new_conf = '\nSETTINGS_BLOCK = """\n'
for cls, p in props_map.items():
new_conf += f"# --- Defaults for {cls} ---\n"
for k in p.__annotations__.keys(): new_conf += f'"{k}": {fmt(getattr(p, k))},\n'
new_conf += "\n"
new_conf += "# --- ARROW_GEOMETRY_PRESETS ---\nARROW_GEOMETRY_PRESETS = {\n"
for n, d in ARROW_GEOMETRY_PRESETS.items(): new_conf += f' "{n}": {{ "shaft_radius": {d["shaft_radius"]}, "cone_radius": {d["cone_radius"]}, "cone_height": {d["cone_height"]} }},\n'
new_conf += "}\n"
new_conf += '"""\n'
# --- ソースコード取得ロジック (エラー修正版) ---
source_code = ""
# 1. テキストエディタのブロック名から取得を試みる
# __file__ が "/Text.003" のようになっている場合、パスを除去して名前だけにする
try:
curr_file = __file__
text_name = os.path.basename(curr_file) # \Text.003 -> Text.003
# Windowsパスセパレータ等が残っている場合の保険
if text_name.startswith('\\') or text_name.startswith('/'): text_name = text_name[1:]
if text_name in bpy.data.texts:
source_code = bpy.data.texts[text_name].as_string()
except NameError: pass
# 2. ファイルシステムから取得を試みる (インストール済みの場合)
if not source_code:
try:
with open(__file__, 'r', encoding='utf-8') as f: source_code = f.read()
except: pass
# 3. inspect (最終手段)
if not source_code:
try: source_code = inspect.getsource(sys.modules[__name__])
except: pass
if not source_code:
self.report({'ERROR'}, "ソースコードの取得に失敗しました。アドオンを保存してから実行してください。")
return {'CANCELLED'}
# 設定ブロックを置換
pattern = r'SETTINGS_BLOCK\s*=\s*""".*?"""'
match = re.search(pattern, source_code, re.DOTALL)
if match:
final_code = source_code[:match.start()] + new_conf.strip() + source_code[match.end():]
new_text = bpy.data.texts.new(name="VectorArrow_Configured.py")
new_text.write(final_code)
# エディタ表示切り替え
for area in context.screen.areas:
if area.type == 'TEXT_EDITOR':
area.spaces[0].text = new_text
break
self.report({'INFO'}, f"新しいスクリプトを作成しました: {new_text.name}")
return {'FINISHED'}
else:
self.report({'ERROR'}, "設定ブロックが見つかりませんでした。")
return {'CANCELLED'}
class ARROW_OT_OpenLink(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.open_link"; bl_label = "リンク"; url: StringProperty()
def execute(self, context): webbrowser.open(self.url); return {'FINISHED'}
class ARROW_OT_RemoveAddon(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.remove_addon"; bl_label = "解除"
def execute(self, context): unregister(); self.report({'INFO'}, "解除しました"); return {'FINISHED'}
class ARROW_OT_CopyShapeInfo(Operator):
bl_idname = f"{ADDON_ID_PREFIX}.copy_shape_info"; bl_label = "情報コピー"; bl_options = {'REGISTER'}
info_string: StringProperty()
def execute(self, context): context.window_manager.clipboard = self.info_string; self.report({'INFO'}, "コピーしました"); return {'FINISHED'}
# ---------------------------------------------------------------------
# パネル
# ---------------------------------------------------------------------
def draw_prop_with_reset(layout, props, prop_name, grp, text=""):
row = layout.row(align=True); row.prop(props, prop_name, text=text)
op = row.operator(ARROW_OT_ResetSingleProperty.bl_idname, text="", icon='LOOP_BACK'); op.prop_group_name = grp; op.prop_name = prop_name
def draw_panel_header(layout, title, pid):
row = layout.row(align=True); row.label(text=title)
op = row.operator(ARROW_OT_ResetPanelProperties.bl_idname, text="", icon='FILE_REFRESH'); op.panel_id = pid
class ARROW_PT_OverlaySettingsPanel(Panel):
bl_idname = "ARROW_PT_overlay_settings"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 1
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout; row = layout.row(align=True)
row.prop(context.scene.overlay_settings, "scale")
row.operator(ARROW_OT_SetOverlayScale.bl_idname, text="1").scale=1.0
row.operator(ARROW_OT_SetOverlayScale.bl_idname, text="10").scale=10.0
row.operator(ARROW_OT_SetOverlayScale.bl_idname, text="100").scale=100.0
class ARROW_PT_Panel1(Panel):
bl_idname = "ARROW_PT_p1"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 2
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout; p = context.scene.adv_vector_arrow_props_p1; s = "adv_vector_arrow_props_p1"
layout.operator(ARROW_OT_CreatePanel1.bl_idname, icon='ADD')
b = layout.box(); draw_panel_header(b, "座標", "P1"); c = b.column(align=True)
draw_prop_with_reset(c,p,"start_x",s,"始X"); draw_prop_with_reset(c,p,"start_y",s,"始Y"); draw_prop_with_reset(c,p,"start_z",s,"始Z")
c.separator(); draw_prop_with_reset(c,p,"end_x",s,"終X"); draw_prop_with_reset(c,p,"end_y",s,"終Y"); draw_prop_with_reset(c,p,"end_z",s,"終Z")
b = layout.box(); draw_panel_header(b, "形状", "P1"); c = b.column(align=True)
L = (Vector((p.end_x,p.end_y,p.end_z))-Vector((p.start_x,p.start_y,p.start_z))).length
c.label(text=f"長さ: {L:.2f}m"); c.prop(p,"cone_only"); c.prop(p,"arrow_shape_preset",text="")
draw_prop_with_reset(c,p,"shaft_radius",s,"軸径"); draw_prop_with_reset(c,p,"cone_radius",s,"傘径"); draw_prop_with_reset(c,p,"cone_height",s,"傘高")
b = layout.box(); draw_panel_header(b, "他", "P1"); c = b.column(align=True)
c.prop(p,"shaft_color",text="軸色"); c.prop(p,"cone_color",text="傘色")
draw_prop_with_reset(c,p,"object_name",s,"名"); draw_prop_with_reset(c,p,"parent_collection_name",s,"親コレ")
class ARROW_PT_Panel2(Panel):
bl_idname = "ARROW_PT_p2"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 3
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout; p = context.scene.adv_vector_arrow_props_p2; s = "adv_vector_arrow_props_p2"
layout.operator(ARROW_OT_CreatePanel2.bl_idname, icon='PLAY')
b = layout.box(); draw_panel_header(b, "座標", "P2"); c = b.column(align=True)
draw_prop_with_reset(c,p,"v1_start_x",s,"V1始X"); draw_prop_with_reset(c,p,"v1_start_y",s,"V1始Y"); draw_prop_with_reset(c,p,"v1_start_z",s,"V1始Z")
c.separator(); draw_prop_with_reset(c,p,"v1_end_x",s,"V1終X"); draw_prop_with_reset(c,p,"v1_end_y",s,"V1終Y"); draw_prop_with_reset(c,p,"v1_end_z",s,"V1終Z")
c.separator(); draw_prop_with_reset(c,p,"v2_end_x",s,"V2終X"); draw_prop_with_reset(c,p,"v2_end_y",s,"V2終Y"); draw_prop_with_reset(c,p,"v2_end_z",s,"V2終Z")
b = layout.box(); draw_panel_header(b, "形状", "P2"); c = b.column(align=True)
c.prop(p,"cone_only"); c.prop(p,"arrow_shape_preset",text="")
draw_prop_with_reset(c,p,"shaft_radius",s,"軸径"); draw_prop_with_reset(c,p,"cone_radius",s,"傘径"); draw_prop_with_reset(c,p,"cone_height",s,"傘高")
b = layout.box(); c = b.column(align=True); c.prop(p,"v1_color"); c.prop(p,"v2_color"); c.prop(p,"v3_color")
class ARROW_PT_Panel3(Panel):
bl_idname = "ARROW_PT_p3"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 4
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout; p = context.scene.adv_vector_arrow_props_p3; s = "adv_vector_arrow_props_p3"
layout.operator(ARROW_OT_CreatePanel3.bl_idname, icon='PLAY')
b = layout.box(); draw_panel_header(b, "座標 (V1+V2=V3)", "P3"); c = b.column(align=True)
draw_prop_with_reset(c,p,"v1_start_x",s,"V1始X"); draw_prop_with_reset(c,p,"v1_start_y",s,"V1始Y"); draw_prop_with_reset(c,p,"v1_start_z",s,"V1始Z")
c.separator(); draw_prop_with_reset(c,p,"v1_end_x",s,"V1終X"); draw_prop_with_reset(c,p,"v1_end_y",s,"V1終Y"); draw_prop_with_reset(c,p,"v1_end_z",s,"V1終Z")
c.separator(); draw_prop_with_reset(c,p,"v2_start_x",s,"V2始X"); draw_prop_with_reset(c,p,"v2_start_y",s,"V2始Y"); draw_prop_with_reset(c,p,"v2_start_z",s,"V2始Z")
c.separator(); draw_prop_with_reset(c,p,"v2_end_x",s,"V2終X"); draw_prop_with_reset(c,p,"v2_end_y",s,"V2終Y"); draw_prop_with_reset(c,p,"v2_end_z",s,"V2終Z")
b = layout.box(); draw_panel_header(b, "形状", "P3"); c = b.column(align=True)
c.prop(p,"cone_only"); c.prop(p,"arrow_shape_preset",text="")
draw_prop_with_reset(c,p,"shaft_radius",s,"軸径"); draw_prop_with_reset(c,p,"cone_radius",s,"傘径"); draw_prop_with_reset(c,p,"cone_height",s,"傘高")
b = layout.box(); c = b.column(align=True); c.prop(p,"v1_color"); c.prop(p,"v2_color"); c.prop(p,"v3_color")
class ARROW_PT_3Axis(Panel):
bl_idname = "ARROW_PT_3axis"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 5
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout; p = context.scene.adv_vector_arrow_props_3axis; s = "adv_vector_arrow_props_3axis"
layout.operator(ARROW_OT_Create3Axis.bl_idname, icon='AXIS_SIDE')
b = layout.box(); draw_panel_header(b, "設定", "3AXIS"); c = b.column(align=True)
draw_prop_with_reset(c,p,"origin_x",s,"原点X"); draw_prop_with_reset(c,p,"origin_y",s,"原点Y"); draw_prop_with_reset(c,p,"origin_z",s,"原点Z")
c.separator(); draw_prop_with_reset(c,p,"axis_length",s,"長さ")
c.prop(p,"arrow_shape_preset",text="形状"); draw_prop_with_reset(c,p,"shaft_radius",s,"軸径"); draw_prop_with_reset(c,p,"cone_radius",s,"傘径"); draw_prop_with_reset(c,p,"cone_height",s,"傘高")
c.separator(); c.prop(p,"x_color",text="X色"); c.prop(p,"y_color",text="Y色"); c.prop(p,"z_color",text="Z色")
class ARROW_PT_GlobalRotatePanel(Panel):
bl_idname = "ARROW_PT_global_rot"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 6
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout; p = context.scene.adv_vector_arrow_props_global_rot; s = "adv_vector_arrow_props_global_rot"
layout.operator(ARROW_OT_RotateGlobal.bl_idname, icon='CON_ROTLIKE')
b = layout.box(); draw_panel_header(b, "回転", "GLOBAL"); c = b.column(align=True)
draw_prop_with_reset(c,p,"rotation_x",s,"X"); draw_prop_with_reset(c,p,"rotation_y",s,"Y"); draw_prop_with_reset(c,p,"rotation_z",s,"Z")
class ARROW_PT_GenerateScriptPanel(Panel):
bl_idname = "ARROW_PT_generate_script"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 7
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
self.layout.operator(ARROW_OT_GenerateScript.bl_idname, icon='TEXT', text="設定を保存してスクリプト出力")
class ARROW_PT_LinksPanel(Panel):
bl_idname = "ARROW_PT_links"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 8
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
for n, u in LINK_LIST: self.layout.operator(ARROW_OT_OpenLink.bl_idname, text=n, icon='URL').url = u
class ARROW_PT_AdminPanel(Panel):
bl_idname = "ARROW_PT_admin"; bl_space_type = 'VIEW_3D'; bl_region_type = 'UI'; bl_order = 9
bl_label = PANEL_CONFIGS[bl_idname][0]; bl_category = TAB_NAME
if not PANEL_CONFIGS[bl_idname][1]: bl_options = {'DEFAULT_CLOSED'}
def draw(self, context): self.layout.operator(ARROW_OT_RemoveAddon.bl_idname, icon='CANCEL')
# ---------------------------------------------------------------------
# 登録
# ---------------------------------------------------------------------
classes = (
OverlaySettings, Panel1Props, Panel2Props, Panel3Props, Panel3AxisProps, GlobalRotationProperties,
ARROW_OT_SetOverlayScale, ARROW_OT_CreatePanel1, ARROW_OT_CreatePanel2, ARROW_OT_CreatePanel3, ARROW_OT_Create3Axis,
ARROW_OT_RotateGlobal, ARROW_OT_OpenLink, ARROW_OT_RemoveAddon, ARROW_OT_ResetSingleProperty,
ARROW_OT_ResetPanelProperties, ARROW_OT_GenerateScript, ARROW_OT_CopyShapeInfo,
ARROW_PT_OverlaySettingsPanel, ARROW_PT_Panel1, ARROW_PT_Panel2, ARROW_PT_Panel3, ARROW_PT_3Axis,
ARROW_PT_GlobalRotatePanel, ARROW_PT_GenerateScriptPanel, ARROW_PT_LinksPanel, ARROW_PT_AdminPanel,
)
def register():
for c in classes: bpy.utils.register_class(c)
s = bpy.types.Scene
s.adv_vector_arrow_props_p1 = PointerProperty(type=Panel1Props)
s.adv_vector_arrow_props_p2 = PointerProperty(type=Panel2Props)
s.adv_vector_arrow_props_p3 = PointerProperty(type=Panel3Props)
s.adv_vector_arrow_props_3axis = PointerProperty(type=Panel3AxisProps)
s.adv_vector_arrow_props_global_rot = PointerProperty(type=GlobalRotationProperties)
s.overlay_settings = PointerProperty(type=OverlaySettings)
def unregister():
for p in ['adv_vector_arrow_props_p1','adv_vector_arrow_props_p2','adv_vector_arrow_props_p3','adv_vector_arrow_props_3axis','adv_vector_arrow_props_global_rot','overlay_settings']:
if hasattr(bpy.types.Scene, p): delattr(bpy.types.Scene, p)
for c in reversed(classes): bpy.utils.unregister_class(c)
if __name__ == "__main__":
try: unregister()
except: pass
register()