diff --git a/molecularnodes/addon.py b/molecularnodes/addon.py index 20b88589..e14b7e89 100644 --- a/molecularnodes/addon.py +++ b/molecularnodes/addon.py @@ -14,7 +14,7 @@ import bpy from bpy.app.handlers import frame_change_pre, load_post, save_post from bpy.props import PointerProperty, CollectionProperty -from .handlers import update_trajectories +from .handlers import update_entities from . import entities, operators, props, session, ui from .utils import add_current_module_to_path from .ui import pref @@ -58,7 +58,7 @@ def register(): save_post.append(session._pickle) load_post.append(session._load) - frame_change_pre.append(update_trajectories) + frame_change_pre.append(update_entities) bpy.types.Scene.MNSession = session.MNSession() # type: ignore bpy.types.Object.uuid = props.uuid_property # type: ignore @@ -88,7 +88,7 @@ def unregister(): save_post.remove(session._pickle) load_post.remove(session._load) - frame_change_pre.remove(update_trajectories) + frame_change_pre.remove(update_entities) del bpy.types.Scene.MNSession # type: ignore del bpy.types.Scene.mn # type: ignore del bpy.types.Scene.interaction_visualiser # type: ignore diff --git a/molecularnodes/assets/MN_data_file_4.2.blend b/molecularnodes/assets/MN_data_file_4.2.blend index d751aece..bd266aca 100644 Binary files a/molecularnodes/assets/MN_data_file_4.2.blend and b/molecularnodes/assets/MN_data_file_4.2.blend differ diff --git a/molecularnodes/blender_manifest.toml b/molecularnodes/blender_manifest.toml index 1a6816f5..f1c811c6 100644 --- a/molecularnodes/blender_manifest.toml +++ b/molecularnodes/blender_manifest.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "molecularnodes" -version = "4.2.10" +version = "4.2.11" name = "Molecular Nodes" tagline = "A toolbox for molecular import and animation in Blender" maintainer = "Brady Johnston" @@ -41,12 +41,12 @@ wheels = [ "./wheels/contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "./wheels/contourpy-1.3.1-cp311-cp311-win_amd64.whl", "./wheels/cycler-0.12.1-py3-none-any.whl", - "./wheels/databpy-0.0.7-py3-none-any.whl", + "./wheels/databpy-0.0.8-py3-none-any.whl", "./wheels/fasteners-0.19-py3-none-any.whl", - "./wheels/fonttools-4.55.3-cp311-cp311-macosx_10_9_universal2.whl", - "./wheels/fonttools-4.55.3-cp311-cp311-macosx_10_9_x86_64.whl", - "./wheels/fonttools-4.55.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "./wheels/fonttools-4.55.3-cp311-cp311-win_amd64.whl", + "./wheels/fonttools-4.55.8-cp311-cp311-macosx_10_9_universal2.whl", + "./wheels/fonttools-4.55.8-cp311-cp311-macosx_10_9_x86_64.whl", + "./wheels/fonttools-4.55.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "./wheels/fonttools-4.55.8-cp311-cp311-win_amd64.whl", "./wheels/joblib-1.4.2-py3-none-any.whl", "./wheels/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", "./wheels/kiwisolver-1.4.8-cp311-cp311-macosx_11_0_arm64.whl", @@ -59,7 +59,7 @@ wheels = [ "./wheels/mda_xdrlib-0.2.0-py3-none-any.whl", "./wheels/mdahole2-0.5.0-py3-none-any.whl", "./wheels/mmtf_python-1.1.3-py2.py3-none-any.whl", - "./wheels/mrcfile-1.5.3-py2.py3-none-any.whl", + "./wheels/mrcfile-1.5.4-py2.py3-none-any.whl", "./wheels/msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", "./wheels/msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", "./wheels/msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", @@ -77,17 +77,17 @@ wheels = [ "./wheels/pillow-11.1.0-cp311-cp311-win_amd64.whl", "./wheels/pyparsing-3.2.1-py3-none-any.whl", "./wheels/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", - "./wheels/pytz-2024.2-py2.py3-none-any.whl", - "./wheels/scipy-1.15.0-cp311-cp311-macosx_10_13_x86_64.whl", - "./wheels/scipy-1.15.0-cp311-cp311-macosx_12_0_arm64.whl", - "./wheels/scipy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "./wheels/scipy-1.15.0-cp311-cp311-win_amd64.whl", + "./wheels/pytz-2025.1-py2.py3-none-any.whl", + "./wheels/scipy-1.15.1-cp311-cp311-macosx_10_13_x86_64.whl", + "./wheels/scipy-1.15.1-cp311-cp311-macosx_12_0_arm64.whl", + "./wheels/scipy-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "./wheels/scipy-1.15.1-cp311-cp311-win_amd64.whl", "./wheels/six-1.17.0-py2.py3-none-any.whl", - "./wheels/starfile-0.5.10-py3-none-any.whl", + "./wheels/starfile-0.5.11-py3-none-any.whl", "./wheels/threadpoolctl-3.5.0-py3-none-any.whl", "./wheels/tqdm-4.67.1-py3-none-any.whl", "./wheels/typing_extensions-4.12.2-py3-none-any.whl", - "./wheels/tzdata-2024.2-py2.py3-none-any.whl", + "./wheels/tzdata-2025.1-py2.py3-none-any.whl", "./wheels/waterdynamics-1.2.0-py3-none-any.whl", ] diff --git a/molecularnodes/entities/trajectory/dna.py b/molecularnodes/entities/trajectory/dna.py index 85f434b0..016f1dbf 100644 --- a/molecularnodes/entities/trajectory/dna.py +++ b/molecularnodes/entities/trajectory/dna.py @@ -56,7 +56,7 @@ def _create_object(self, style: str = "oxdna", name: str = "NewUniverseObject"): return self.object - def _update_positions(self, frame: int) -> None: + def set_frame(self, frame: int) -> None: super()._update_positions(frame) self._update_timestep_values() diff --git a/molecularnodes/handlers.py b/molecularnodes/handlers.py index cfbdaceb..2c475f7e 100644 --- a/molecularnodes/handlers.py +++ b/molecularnodes/handlers.py @@ -1,28 +1,17 @@ import bpy from bpy.app.handlers import persistent -# from .session import update_trajectories - -# from .session import MNSession # this update function requires a self and context input, as funcitons with these inputs # have ot be passed to the `update` arguments of UI properties. When the UI is updated, # the function is called with the UI element being `self` and the current context being # passed into the function -def _update_trajectories(self, context: bpy.types.Context) -> None: - """ - Function for being called at various points in the updating of the UI, to ensure - positions and selections of the trajectories are udpated with the new inputs - """ - update_trajectories(context.scene) - - -def _update_trajectories_on_frame_change(self, context: bpy.types.Context) -> None: +def _udpate_entities(self, context: bpy.types.Context) -> None: """ Function for being called at various points in the updating of the UI, to ensure positions and selections of the trajectories are udpated with the new inputs """ - update_trajectories(context.scene) + update_entities(context.scene) def _selection_update_trajectories(self, context: bpy.types.Context) -> None: @@ -34,7 +23,7 @@ def _selection_update_trajectories(self, context: bpy.types.Context) -> None: if self.immutable: return else: - update_trajectories(context.scene) + update_entities(context.scene) # this is the 'perisisent' function which can be appended onto the @@ -43,17 +32,24 @@ def _selection_update_trajectories(self, context: bpy.types.Context) -> None: # use the `frame_change_pre` handler as we want the frame to change first, then we update # the universe based on the current frame value @persistent -def update_trajectories(scene): - "Call the set_frame method of all trajectories in the current session" +def update_entities(scene): + "Call the `set_frame()` method of all entities in the current session" session = scene.MNSession - for traj in session.trajectories.values(): + for entity in session.entities.values(): # use the updated method if it exists but otherwise fallback on the old method # of updating the trajectories - if hasattr(traj, "update_with_scene"): - if traj.update_with_scene: - traj.set_frame(scene.frame_current) + + if hasattr(entity, "update_with_scene"): + if entity.update_with_scene: + frame_to_set = scene.frame_current else: - traj.set_frame(traj.frame) + frame_to_set = entity.frame + + # do the entity setting, if the method isn't implemented, just pass + try: + entity.set_frame(frame_to_set) + except NotImplementedError: + pass else: traj._update_positions(scene.frame_current) diff --git a/molecularnodes/props.py b/molecularnodes/props.py index 9e07ea79..2b952de2 100644 --- a/molecularnodes/props.py +++ b/molecularnodes/props.py @@ -1,7 +1,7 @@ import bpy from bpy.types import PropertyGroup from bpy.props import IntProperty, BoolProperty, EnumProperty, StringProperty -from .handlers import _selection_update_trajectories, _update_trajectories +from .handlers import _selection_update_trajectories, _udpate_entities from .style import STYLE_ITEMS @@ -117,39 +117,39 @@ class MolecularNodesObjectProperties(PropertyGroup): name="Frame", description="Frame of the loaded trajectory", default=0, - update=_update_trajectories, + update=_udpate_entities, min=0, ) update_with_scene: BoolProperty( # type: ignore name="Update with Scene", description="Update the trajectory with the scene frame", default=True, - update=_update_trajectories, + update=_udpate_entities, ) subframes: IntProperty( # type: ignore name="Subframes", description="Number of subframes to insert between frames of the loaded trajectory", default=0, - update=_update_trajectories, + update=_udpate_entities, min=0, ) offset: IntProperty( # type: ignore name="Offset", description="Offset the starting playback for the trajectory on the timeine. Positive starts the playback later than frame 0, negative starts it earlier than frame 0", default=0, - update=_update_trajectories, + update=_udpate_entities, ) interpolate: BoolProperty( # type: ignore name="Interpolate", description="Whether to interpolate when using subframes", default=True, - update=_update_trajectories, + update=_udpate_entities, ) average: IntProperty( # type: ignore name="Average", description="Average the position this number of frames either side of the current frame", default=0, - update=_update_trajectories, + update=_udpate_entities, min=0, soft_max=5, ) @@ -157,7 +157,7 @@ class MolecularNodesObjectProperties(PropertyGroup): name="Correct", description="Correct for periodic boundary crossing when using interpolation or averaging. Assumes cubic dimensions and only works if the unit cell is orthorhombic", default=False, - update=_update_trajectories, + update=_udpate_entities, ) filepath_trajectory: StringProperty( # type: ignore name="Trajectory", @@ -265,7 +265,7 @@ def execute(self, context): i = int(len(obj.mn_trajectory_selections) - 1) obj.mn_trajectory_selections[i].name = f"selection_{i + 1}" obj.mn["list_index"] = i - _update_trajectories(self, context) + _udpate_entities(self, context) return {"FINISHED"} @@ -286,7 +286,7 @@ def execute(self, context): sel_list = obj.mn_trajectory_selections sel_list.remove(index) obj.mn.trajectory_selection_index = len(sel_list) - 1 - _update_trajectories(self, context) + _udpate_entities(self, context) return {"FINISHED"} diff --git a/molecularnodes/ui/node_info.py b/molecularnodes/ui/node_info.py index e45a03af..18432c26 100644 --- a/molecularnodes/ui/node_info.py +++ b/molecularnodes/ui/node_info.py @@ -866,6 +866,23 @@ videos="https://imgur.com/FcEXSZx", ), Break(), + MenuItem( + name="Falloff Object", + description="Falloff computed from the location on the input object", + ), + MenuItem( + name="Falloff Geometry", + description="Falloff computed from the proximity of the nearest geometry", + ), + MenuItem( + name="Noise Vector", + description="Noise that can be evolved over time with `Animate` based on the `Position` attribute", + ), + MenuItem( + name="Noise Repeat", + description="Noise that repeats ever x period, based on some of the `Position` attribute", + ), + Break(), MenuItem( label="Noise Position", name="MN_animate_noise_position", diff --git a/pyproject.toml b/pyproject.toml index 4aaba6fd..eacc7a8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "molecularnodes" -version = "4.2.10" +version = "4.2.11" description = "Toolbox for molecular animations with Blender and Geometry Nodes." readme = "README.md" dependencies = ["databpy", "MDAnalysis>=2.7.0", "biotite~=0.40", "mrcfile", "starfile"]