diff --git a/How to do without.md b/How to do without.md new file mode 100644 index 0000000..98bd76a --- /dev/null +++ b/How to do without.md @@ -0,0 +1,24 @@ +## To save and reload multiple 3D cursors using Empties in Blender, you can follow these steps: + +### Save 3D Cursor Location and Rotation to an Empty + +1. **Add an Empty Aligned to the 3D Cursor:** + - Position your 3D cursor where you want to save its location and rotation. + - Press `Shift + A` to open the Add menu. + - Select `Empty` and choose the type of Empty you prefer (e.g., Plain Axes). + - Press `F9` and select Align to `3D cursor`. + +### Load Empty Location and Rotation to the 3D Cursor + +1. **Snap setup:** + - Using the Cursor tool. + - In the tool setting, set to orientation: `Transform`. + - In the 3D viewport `Header ‣ Transform Orientation`, select `Local`. + - In the 3D viewport `Header ‣ Snap`, select `Vertex` and toggle it on. + +2. **Usage:** + - Using the Cursor tool. + - In the Outliner, select the Empty object you created. + - In the 3D viewport, click next to the selected Empty and snap the 3D cursor to the Empty. + +This method allows you to save multiple 3D cursor positions and orientations using Empties, at least in object mode. For edit mode, you need to [save the Empties transform orientation](https://docs.blender.org/manual/en/dev/editors/3dview/controls/orientation.html#bpy-ops-transform-create-orientation) in object mode first. \ No newline at end of file diff --git a/README.md b/README.md index c67e217..3909815 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,49 @@ # Welcome to 3D Cursors Briefcase 💼 -Take control of your 3D cursor in Blender like never before! -With 3D Cursors Briefcase, you can save, load, and manage multiple 3D cursors. -Try it today and launch your 3D Cursors experience! 🚀 +Take control of your 3D cursor in Blender like never before! With 3D Cursors Briefcase, you can save, load, and manage multiple 3D cursors. Try it today and launch your 3D Cursors experience! 🚀 # Installation ⚙️ + For Blender 4.2 LTS: -- [Download zip](https://extensions.blender.org/download/sha256:a64c363d8794a0be75c482ddce5ee72ca9eb55a10299c65afca9072798eb6da0/add-on-c3db-v0.0.6.zip?repository=%2Fapi%2Fv1%2Fextensions%2F&blender_version_min=4.2.0) -- Drag-and-drop extension .zip package into Blender. +- [Download zip](https://extensions.blender.org/download/sha256:020efcab892a3bb3db8d18086fd7b092af0160a1c85f8575c75a3818005dde48/add-on-c3db-v0.0.7.zip?repository=%2Fapi%2Fv1%2Fextensions%2F&blender_version_min=4.2.0) +- Drag-and-drop the extension .zip package into Blender. -For 3.3 LTS and 3.6 LTS go to [ Sidebar > View Tab`. - - In the `3D Cursor` panel. - - Look for the `3D Cursors Briefcase` sub-panel. +- In the `3D Cursor` panel. +- Look for the `3D Cursors Briefcase` sub-panel. - ![user interface](3d-cursors-case-guide.png "user interface") +![user interface](3d-cursors-case-guide.png "user interface") 1. **Saving a 3D Cursor:** - - Position your 3D cursor in the desired location and rotation. - - Click on the `+` button. This will save the current position and rotation of the 3D cursor. + - Position your 3D cursor in the desired location and rotation. + - Click on the `+` button. This will save the current position and rotation of the 3D cursor. 2. **Deleting a 3D Cursor:** - - Select the saved 3D cursor from the list. - - Click on the `-` button. This will remove the selected 3D cursor from the list. + - Select the saved 3D cursor from the list. + - Click on the `-` button. This will remove the selected 3D cursor from the list. 3. **Moving a 3D Cursor Up/Down in the List:** - - Select the saved 3D cursor from the list. - - Click on the `🞁` or `🞃` button to change the order of the selected 3D cursor in the list. + - Select the saved 3D cursor from the list. + - Click on the `🞁` or `🞃` button to change the order of the selected 3D cursor in the list. 4. **Loading a 3D Cursor:** - - Select the saved 3D cursor from the list. - - Click on the `Load` button. This will move the 3D cursor to the saved location and rotation. + - Select the saved 3D cursor from the list. + - Click on the `Load` button. This will move the 3D cursor to the saved location and rotation. 5. **Going to a 3D Cursor:** - - Click on the `Centre View` button. Centers the view on the 3D Cursor. - - Use the checkbox to Automaticely Centre View when Loading a 3D Cursor + - Click on the `Centre View` button. This centers the view on the 3D cursor. + - Use the checkbox to automatically center the view when loading a 3D cursor. -6. **3D Cursor Specials menu:** - - Load previous 3D Cursor : Go to the previous 3D Cursor and Load/Restore it. - - Load next 3D Cursor : Go to the next 3D Cursor and Load/Restore it. - - Update 3D Cursor : Update selected 3D Cursor. - - Delete All 3D Cursors : Delete all 3D Cursors from the list. - -[LICENSE](LICENSE) +6. **3D Cursor Specials Menu:** + - Load previous 3D Cursor: Go to the previous 3D cursor and load/restore it. + - Load next 3D Cursor: Go to the next 3D cursor and load/restore it. + - Update 3D Cursor: Update the selected 3D cursor. + - Delete All 3D Cursors: Delete all 3D cursors from the list. + - Convert Selected to Empty: Convert the selected 3D cursor to an empty object (make sure you are in Object Mode). + - Convert All to Empties: Convert all saved 3D cursors to empty objects (make sure you are in Object Mode). + +[LICENSE](LICENSE) \ No newline at end of file diff --git a/__init__.py b/__init__.py index c0ecbce..177ab3f 100644 --- a/__init__.py +++ b/__init__.py @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-3.0-or-later +# https://extensions.blender.org/add-ons/c3db/ + import bpy +from mathutils import Quaternion +from mathutils import Vector class C3DB_PG_properties(bpy.types.PropertyGroup): @@ -21,12 +25,15 @@ class C3DB_MT_menu_specials(bpy.types.Menu): def draw(self, context): layout = self.layout - layout.operator("c3db.restore_previous") - layout.operator("c3db.restore_next") + layout.operator("c3db.restore_previous", icon="TRIA_UP_BAR") + layout.operator("c3db.restore_next", icon="TRIA_DOWN_BAR") layout.separator() - layout.operator("c3db.update") + layout.operator("c3db.update", icon="FILE_REFRESH") layout.separator() - layout.operator("c3db.delete_all") + layout.operator("c3db.delete_all", icon="TRASH") + layout.separator() + layout.operator("c3db.convert_selected_to_empty", icon="OUTLINER") + layout.operator("c3db.convert_all_to_empties") class C3DB_UL_list(bpy.types.UIList): @@ -212,6 +219,14 @@ class C3DB_OT_delete_all(bpy.types.Operator): bl_label = "Delete All 3D Cursors" bl_options = {"REGISTER", "UNDO"} + @classmethod + def poll(cls, context): + return bool( + context.scene.C3DB_3Dcursors_collection + ) and context.scene.C3DB_3Dcursors_index < len( + context.scene.C3DB_3Dcursors_collection + ) + def execute(self, context): context.scene.C3DB_3Dcursors_collection.clear() context.area.tag_redraw() # Refresh the UI @@ -289,6 +304,88 @@ class C3DB_OT_move_down_list(bpy.types.Operator): return {"FINISHED"} +class C3DB_OT_convert_all_to_empties(bpy.types.Operator): + """Convert all 3D Cursors to empty objects. This operator is inactive if: You are not in Object Mode ...""" + + bl_idname = "c3db.convert_all_to_empties" + bl_label = "Convert All 3D Cursors to Empties" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return ( + bool(context.scene.C3DB_3Dcursors_collection) + and context.scene.C3DB_3Dcursors_index + < len(context.scene.C3DB_3Dcursors_collection) + and context.mode == "OBJECT" + ) + + def execute(self, context): + for c3db_3d_cursor in context.scene.C3DB_3Dcursors_collection: + if c3db_3d_cursor.rotation_mode == "QUATERNION": + rotation = Quaternion(c3db_3d_cursor.rotation_quaternion) + rotation_euler = rotation.to_euler() + elif c3db_3d_cursor.rotation_mode == "AXIS_ANGLE": + rotation = Quaternion( + Vector(c3db_3d_cursor.rotation_axis_angle).yzw, + c3db_3d_cursor.rotation_axis_angle[0], + ) + rotation_euler = rotation.to_euler() + else: + rotation_euler = c3db_3d_cursor.rotation_euler + + bpy.ops.object.empty_add( + type="PLAIN_AXES", + radius=1, + location=c3db_3d_cursor.location, + rotation=rotation_euler, + ) + + bpy.context.object.name = c3db_3d_cursor.name + + return {"FINISHED"} + + +class C3DB_OT_convert_selected_to_empty(bpy.types.Operator): + """Convert selected 3D Cursor to an empty object. This operator is inactive if: You are not in Object Mode ...""" + + bl_idname = "c3db.convert_selected_to_empty" + bl_label = "Convert Selected 3D Cursor to Empty" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return ( + context.scene.C3DB_3Dcursors_collection + and context.scene.C3DB_3Dcursors_index + < len(context.scene.C3DB_3Dcursors_collection) + and context.mode == "OBJECT" + ) + + def execute(self, context): + item = context.scene.C3DB_3Dcursors_collection[ + context.scene.C3DB_3Dcursors_index + ] + if item.rotation_mode == "QUATERNION": + rotation = Quaternion(item.rotation_quaternion) + rotation_euler = rotation.to_euler() + elif item.rotation_mode == "AXIS_ANGLE": + rotation = Quaternion( + Vector(item.rotation_axis_angle).yzw, item.rotation_axis_angle[0] + ) + rotation_euler = rotation.to_euler() + else: + rotation_euler = item.rotation_euler + + bpy.ops.object.empty_add( + type="PLAIN_AXES", radius=1, location=item.location, rotation=rotation_euler + ) + + bpy.context.object.name = item.name + + return {"FINISHED"} + + class C3DB_PT_panel(bpy.types.Panel): bl_label = "3D Cursors Briefcase" bl_idname = "C3DB_PT_panel" @@ -342,6 +439,8 @@ classes = ( C3DB_OT_remove_from_list, C3DB_OT_move_up_list, C3DB_OT_move_down_list, + C3DB_OT_convert_all_to_empties, + C3DB_OT_convert_selected_to_empty, C3DB_PT_panel, ) diff --git a/blender_manifest.toml b/blender_manifest.toml index a33a6bb..26b3221 100644 --- a/blender_manifest.toml +++ b/blender_manifest.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "C3DB" name = "3D Cursors Briefcase" -version = "0.0.6" +version = "0.0.7" tagline = "Store and manage multiple 3D Cursors" maintainer = "dupoxy" type = "add-on" diff --git a/extensions.blender.org/Featured image.png b/extensions.blender.org/Featured image.png index 8b97d42..b812601 100644 Binary files a/extensions.blender.org/Featured image.png and b/extensions.blender.org/Featured image.png differ