Не подтверждена Коммит 8ce580ae создал по автору Victor Doval's avatar Victor Doval Зафиксировано автором GitHub
Просмотр файлов

New "List Item Insert" and "Mask To Index" nodes (#2512)

* New list_item_insert and mask_to_index nodes

* moved ListItem2Node to old_nodes and added replacement operator

* cleaning and adaptative socket fixed

* List Item Node Input "Item" renamed "Index"
владелец 09c012e4
Mask To Index
=============
Functionality
-------------
This node generates a mask list ([True, False,..]) based on a index list (the True values) and a length or data-set
Inputs
------
**Index**: Index of the True values
**Mask Length**: Length of the mask list
**data to mask**: when **data masking** is enabled the node will take the shape of the input data
Parameters
----------
**data masking**: When enabled the length of the mask will be taken from the **data to mask** input.
**Topo mask**: When enabled the mask will taken from the **data to mask** input but one level above, this is handy to mask vector lists or edge/polygon lists
Outputs
-------
**Mask:** Mask List
Example
-------
.. image:: https://github.com/vicdoval/sverchok/raw/docs_images/images_for_docs/list_mask/index_to_mask/index_to_mask.png
:alt: index_to_mask_sverchok_blender_example.png
......@@ -8,4 +8,5 @@ List Masks
mask
mask_join
mask_converter
mask_to_index
index_to_mask
Mask To Index
=============
Functionality
-------------
This node use transforms a mask list ( [0,1,0..] or [False, True, False..]) in to two lists, one with the True (or 1) indexes and the othe with the false (or 0) indexes.
Inputs
------
**Mask:** Input socket for True / False Data list.
Outputs
-------
**True Index:** Input socket for True Data list.
**False Index:** Input socket for False Data list.
Example
-------
.. image:: https://github.com/vicdoval/sverchok/raw/docs_images/images_for_docs/list_mask/mask_to_index/mask_to_index.png
:alt: compass_3d_sverchok_blender_example.png
......@@ -4,7 +4,7 @@ List Item
Functionality
-------------
Select items from list based on index. The node is *data type agnostic*, meaning it makes no assumptions about the data you feed it. It shoudld accepts any type of data native to Sverchok..
Select items from list based on index. The node is *data type agnostic*, meaning it makes no assumptions about the data you feed it. It should accepts any type of data native to Sverchok..
Inputs
------
......@@ -12,9 +12,9 @@ Inputs
+--------+--------------------------------------------------------------------------+
| Input | Description |
+========+==========================================================================+
| Data | The data - can be anything |
| Data | The data - can be anything |
+--------+--------------------------------------------------------------------------+
| item | Item(s) to select, allows negative index python index |
| Index | Index of Item(s) to select, allows negative index python index |
+--------+--------------------------------------------------------------------------+
Parameters
......@@ -25,9 +25,9 @@ Parameters
It is essentially how many chained element look-ups you do on a list. If ``SomeList`` has a considerable *nestedness* then you might access the most atomic element of the list doing ``SomeList[0][0][0][0]``. Levels in this case would be 4.
**item**
**Index**
A list of items to select, allow negative index python indexing so that -1 the last element. The items doesn't have to be in order and a single item can be selected more than a single time.
A list of indexes of the items to select, allow negative index python indexing so that -1 the last element. The items doesn't have to be in order and a single item can be selected more than a single time.
Outputs
-------
......
List Item Insert
================
Functionality
-------------
Inserts items in a list at desired index. It can replace that index or move all the elements of the list to the right.
The node is *data type agnostic*, meaning it makes no assumptions about the data you feed it. It should accepts any type of data native to Sverchok...
Inputs
------
+--------+--------------------------------------------------------------------------+
| Input | Description |
+========+==========================================================================+
| Data | The data - can be anything |
+--------+--------------------------------------------------------------------------+
| Item | Item(s) to insert |
+--------+--------------------------------------------------------------------------+
| Index | Index in which element will be inserted, allows negative index |
+--------+--------------------------------------------------------------------------+
Parameters
----------
**Level**
It is essentially how many chained element look-ups you do on a list. If ``SomeList`` has a considerable *nestedness* then you might access the most atomic element of the list doing ``SomeList[0][0][0][0]``. Levels in this case would be 4.
**Replace**
When activated the node will replace the item at desired index. When disabled the element will be added and all the element after the index will move to the right.
**Index**
A list of items to select, allow negative index python indexing so that -1 the last element. The items doesn't have to be in order and a single item can be selected more than a single time.
Advanced Parameters
-------------------
Available in the N-panel and in the Right-click Menu:
**List Match Local**
In case of having different list lengths between Index and Item inputs the data will be matched according to the selected behavior. The default behavior is to match the longest list by repeating the last element of the short list (Match Long Repeat).
Outputs
-------
**Data**: the list with the items inserted.
Examples
--------
Trying various inputs, adjusting the parameters, and piping the output to a *Debug Print* (or stethoscope) node will be the fastest way to acquaint yourself with the inner workings of the *List Item Insert* Node.
.. image:: https://github.com/vicdoval/sverchok/raw/docs_images/images_for_docs/list_struct/list_item_insert/list_item_insert.png
:alt: insert_item_in_list_sverchok_blender_example.png
......@@ -7,6 +7,7 @@ List Struct
flip
item
item_insert
repeater
reverse
shift_mk2
......
......@@ -136,6 +136,8 @@
MaskListNode
SvMaskJoinNode
SvMaskConvertNode
SvMaskToIndexNode
SvIndexToMaskNode
## List Mutators
SvListModifierNode
......@@ -158,7 +160,8 @@
ListSliceNode
SvListSplitNode
ListFLNode
ListItem2Node
SvListItemNode
SvListItemInsertNode
ListReverseNode
ListShuffleNode
ListSortNodeMK2
......@@ -349,7 +352,6 @@
SvCacheNode
SvUVtextureNode
SvSeparateMeshNodeMK2
SvIndexToMaskNode
SvMultiExtrudeAlt
SvOffsetLineNode
SvContourNode
......
......@@ -29,15 +29,16 @@ class SvIndexToMaskNode(bpy.types.Node, SverchCustomTreeNode):
bl_idname = 'SvIndexToMaskNode'
bl_label = 'Index To Mask'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_INDEX_TO_MASK'
ML: IntProperty(name='Mask Length', default=10, min=2, update=updateNode)
def update_mode(self, context):
self.inputs['mask size'].hide_safe = self.data_to_mask
self.inputs['data to mask'].hide_safe = not self.data_to_mask
updateNode(self, context)
data_to_mask: BoolProperty(name = "data masking",
data_to_mask: BoolProperty(name="data masking",
description = "Use data to define mask length",
default = False,
update=update_mode)
......
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
from copy import copy
import bpy
from bpy.props import StringProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
class SvMaskToIndexNode(bpy.types.Node, SverchCustomTreeNode):
'''
Triggers: Index list from mask list
Tooltip: Splits the true and false indices from a mask list
'''
bl_idname = 'SvMaskToIndexNode'
bl_label = 'Mask to Index'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_MASK_TO_INDEX'
def sv_init(self, context):
self.inputs.new('SvStringsSocket', "Mask")
self.outputs.new('SvStringsSocket', "True Index")
self.outputs.new('SvStringsSocket', "False Index")
def process(self):
inputs = self.inputs
outputs = self.outputs
if not (any(s.is_linked for s in outputs) and inputs[0].is_linked):
return
mask = inputs['Mask'].sv_get(default=[[1, 0]])
if self.outputs['True Index'].is_linked:
outputs['True Index'].sv_set(self.true_indices(mask))
if self.outputs['False Index'].is_linked:
outputs['False Index'].sv_set(self.false_indices(mask))
def true_indices(self, mask):
if type(mask[0]) in [list, tuple]:
return [self.true_indices(m) for m in mask]
else:
return [i for i, m in enumerate(mask) if m]
def false_indices(self, mask):
if type(mask[0]) in [list, tuple]:
return [self.false_indices(m) for m in mask]
else:
return [i for i, m in enumerate(mask) if not m]
def register():
bpy.utils.register_class(SvMaskToIndexNode)
def unregister():
bpy.utils.unregister_class(SvMaskToIndexNode)
......@@ -22,76 +22,90 @@ from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import (changable_sockets, repeat_last, updateNode)
# ListItem2
# Allows a list of items, with both negative and positive index and repeated values
# SvListItemNode
# Allows a list of indexes, with both negative and positive index and repeated values
# Other output is not wrapped.
# Based on ListItem
# For now only accepts one list of items
# by Linus Yng
# For now only accepts one list of indexes
# Based on ListItem2 by Linus Yng
class ListItem2Node(bpy.types.Node, SverchCustomTreeNode):
''' List item '''
bl_idname = 'ListItem2Node'
class SvListItemNode(bpy.types.Node, SverchCustomTreeNode):
'''
Triggers: List Item Out
Tooltip: Get elements from list at desired indexes
'''
bl_idname = 'SvListItemNode'
bl_label = 'List Item'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_LIST_ITEM'
level: IntProperty(name='level_to_count', default=2, min=0, update=updateNode)
item: IntProperty(name='item', default=0, update=updateNode)
level: IntProperty(name='level_to_count', default=2, min=1, update=updateNode)
index: IntProperty(name='Index', default=0, update=updateNode)
typ: StringProperty(name='typ', default='')
newsock: BoolProperty(name='newsock', default=False)
def draw_buttons(self, context, layout):
'''draw buttons on the node'''
layout.prop(self, "level", text="level")
def sv_init(self, context):
'''create sockets'''
self.inputs.new('SvStringsSocket', "Data")
self.inputs.new('SvStringsSocket', "Item").prop_name = 'item'
self.inputs.new('SvStringsSocket', "Index").prop_name = 'index'
self.outputs.new('SvStringsSocket', "Item")
self.outputs.new('SvStringsSocket', "Other")
def migrate_from(self, old_node):
self.index = old_node.item
def update(self):
'''adapt socket type to input type'''
if 'Data' in self.inputs and self.inputs['Data'].links:
inputsocketname = 'Data'
outputsocketname = ['Item', 'Other']
changable_sockets(self, inputsocketname, outputsocketname)
def process(self):
if self.inputs['Data'].is_linked:
OItem, OOther = self.outputs
'''main node function called every update'''
if self.inputs['Data'].is_linked and self.inputs['Index'].is_linked:
out_item, out_other = self.outputs
data = self.inputs['Data'].sv_get()
items = self.inputs['Item'].sv_get([[self.item]])
if OItem.is_linked:
indexes = self.inputs['Index'].sv_get([[self.index]])
if out_item.is_linked:
if self.level-1:
out = self.get(data, self.level-1, items, self.get_items)
out = self.get(data, self.level-1, indexes, self.get_items)
else:
out = self.get_items(data, items[0])
OItem.sv_set(out)
if OOther.is_linked:
out = self.get_items(data, indexes[0])
out_item.sv_set(out)
if out_other.is_linked:
if self.level-1:
out = self.get(data, self.level-1, items, self.get_other)
out = self.get(data, self.level-1, indexes, self.get_other)
else:
out = self.get_other(data, items[0])
OOther.sv_set(out)
out = self.get_other(data, indexes[0])
out_other.sv_set(out)
def get_items(self, data, items):
def get_items(self, data, indexes):
'''extract the indexes from the list'''
if type(data) in [list, tuple]:
return [data[item] for item in items if item < len(data) and item >= -len(data)]
return [data[index] for index in indexes if -len(data) <= index < len(data)]
else:
return None
def get_other(self, data, items):
def get_other(self, data, indexes):
'''remove the indexes from the list'''
is_tuple = False
if type(data) == tuple:
data = list(data)
is_tuple = True
if type(data) == list:
m_items = items.copy()
for idx, item in enumerate(items):
if item < 0:
m_items[idx] = len(data)-abs(item)
for i in sorted(set(m_items), reverse=True):
if i < len(data) and i > -1:
m_indexes = indexes.copy()
for idx, index in enumerate(indexes):
if index < 0:
m_indexes[idx] = len(data)-abs(index)
for i in sorted(set(m_indexes), reverse=True):
if -1 < i < len(data):
del data[i]
if is_tuple:
return tuple(data)
......@@ -100,19 +114,22 @@ class ListItem2Node(bpy.types.Node, SverchCustomTreeNode):
else:
return None
def get(self, data, level, items, f):
def get(self, data, level, indexes, func):
'''iterative fucntion to get down to the requested level'''
if level == 1:
item_iter = repeat_last(items)
return [self.get(obj, level-1, next(item_iter), f) for obj in data]
index_iter = repeat_last(indexes)
return [self.get(obj, level-1, next(index_iter), func) for obj in data]
elif level:
return [self.get(obj, level-1, items, f) for obj in data]
return [self.get(obj, level-1, indexes, func) for obj in data]
else:
return f(data, items)
return func(data, indexes)
def register():
bpy.utils.register_class(ListItem2Node)
'''register class in Blender'''
bpy.utils.register_class(SvListItemNode)
def unregister():
bpy.utils.unregister_class(ListItem2Node)
'''unregister class in Blender'''
bpy.utils.unregister_class(SvListItemNode)
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
from bpy.props import BoolProperty, IntProperty, StringProperty, EnumProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import (changable_sockets, repeat_last, updateNode, list_match_func, list_match_modes)
# ListItem2
# Allows a list of items, with both negative and positive index and repeated values
# Other output is not wrapped.
# Based on ListItem
# For now only accepts one list of items
# by Linus Yng
class SvListItemInsertNode(bpy.types.Node, SverchCustomTreeNode):
'''
Triggers: List Item In
Tooltip: Insert elements in list at desired indexes
'''
bl_idname = 'SvListItemInsertNode'
bl_label = 'List Item Insert'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_LIST_ITEM_INSERT'
level: IntProperty(name='level_to_count', default=2, min=0, update=updateNode)
index: IntProperty(name='index', default=0, update=updateNode)
replace: BoolProperty(name='Replace', default=False, update=updateNode)
list_match_local: EnumProperty(
name="Match Local",
description="Behavior on different list lengths between Index and Item lists",
items=list_match_modes, default="REPEAT",
update=updateNode)
typ: StringProperty(name='typ', default='')
newsock: BoolProperty(name='newsock', default=False)
def draw_buttons(self, context, layout):
layout.prop(self, "level", text="level")
layout.prop(self, "replace", text="Replace")
def draw_buttons_ext(self, context, layout):
'''draw buttons on the N-panel'''
layout.prop(self, "level", text="level")
layout.prop(self, "replace", text="Replace")
layout.separator()
layout.label(text="List Match:")
layout.prop(self, "list_match_local", text="Item-Index", expand=False)
def rclick_menu(self, context, layout):
'''right click sv_menu items'''
layout.prop(self, "level", text="level")
layout.prop(self, "replace", text="Replace")
layout.prop_menu_enum(self, "list_match_local", text="List Match Item-Index")
def sv_init(self, context):
self.inputs.new('SvStringsSocket', "Data")
self.inputs.new('SvStringsSocket', "Item")
self.inputs.new('SvStringsSocket', "Index").prop_name = 'index'
self.outputs.new('SvStringsSocket', "Data")
def update(self):
if 'Data' in self.inputs and self.inputs['Data'].links:
inputsocketname = 'Data'
outputsocketname = ['Data']
changable_sockets(self, inputsocketname, outputsocketname)
def process(self):
out_socket = self.outputs[0]
si = self.inputs
if si['Data'].is_linked and out_socket.is_linked:
data = si['Data'].sv_get()
if si['Item'].is_linked:
new_item = si['Item'].sv_get()
indexes = si['Index'].sv_get([[self.index]])
if self.level-1:
out = self.get(data, new_item, self.level-1, indexes, self.set_items)
else:
out = self.set_items(data, new_item, indexes[0])
out_socket.sv_set(out)
else:
out_socket.sv_set(data)
def set_items(self, data, new_items, indexes):
if type(data) in [list, tuple]:
params = list_match_func[self.list_match_local]([indexes, new_items])
for ind, i in zip(*params):
if self.replace and len(data) > ind:
data.pop(ind)
data.insert(ind, i)
return data
return None
def get(self, data, new_items, level, items, f):
if level == 1:
item_iter = repeat_last(items)
new_item_iter = repeat_last(new_items)
return [self.get(obj, next(new_item_iter), level-1, next(item_iter), f) for obj in data]
elif level:
return [self.get(obj, new_items, level-1, items, f) for obj in data]
else:
return f(data, new_items, items)
def register():
bpy.utils.register_class(SvListItemInsertNode)
def unregister():
bpy.utils.unregister_class(SvListItemInsertNode)
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
from bpy.props import BoolProperty, IntProperty, StringProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import (changable_sockets, repeat_last, updateNode)
# ListItem2
# Allows a list of items, with both negative and positive index and repeated values
# Other output is not wrapped.
# Based on ListItem
# For now only accepts one list of items
# by Linus Yng
class ListItem2Node(bpy.types.Node, SverchCustomTreeNode):
''' List item '''
bl_idname = 'ListItem2Node'
bl_label = 'List Item'
bl_icon = 'OUTLINER_OB_EMPTY'
replacement_nodes = [('SvListItemNode', {"Item":"Index"}, None)]
level: IntProperty(name='level_to_count', default=2, min=0, update=updateNode)
item: IntProperty(name='item', default=0, update=updateNode)
typ: StringProperty(name='typ', default='')
newsock: BoolProperty(name='newsock', default=False)
def draw_buttons(self, context, layout):
layout.prop(self, "level", text="level")
def sv_init(self, context):
self.inputs.new('SvStringsSocket', "Data")
self.inputs.new('SvStringsSocket', "Item").prop_name = 'item'
self.outputs.new('SvStringsSocket', "Item")
self.outputs.new('SvStringsSocket', "Other")
def update(self):
if 'Data' in self.inputs and self.inputs['Data'].links:
inputsocketname = 'Data'
outputsocketname = ['Item', 'Other']
changable_sockets(self, inputsocketname, outputsocketname)
def process(self):
if self.inputs['Data'].is_linked:
OItem, OOther = self.outputs
data = self.inputs['Data'].sv_get()
items = self.inputs['Item'].sv_get([[self.item]])
if OItem.is_linked:
if self.level-1:
out = self.get(data, self.level-1, items, self.get_items)
else:
out = self.get_items(data, items[0])
OItem.sv_set(out)
if OOther.is_linked:
if self.level-1:
out = self.get(data, self.level-1, items, self.get_other)
else:
out = self.get_other(data, items[0])
OOther.sv_set(out)
def get_items(self, data, items):
if type(data) in [list, tuple]:
return [data[item] for item in items if item < len(data) and item >= -len(data)]
else:
return None
def get_other(self, data, items):
is_tuple = False
if type(data) == tuple:
data = list(data)
is_tuple = True
if type(data) == list:
m_items = items.copy()
for idx, item in enumerate(items):
if item < 0:
m_items[idx] = len(data)-abs(item)
for i in sorted(set(m_items), reverse=True):
if i < len(data) and i > -1:
del data[i]
if is_tuple:
return tuple(data)
else:
return data
else:
return None
def get(self, data, level, items, f):
if level == 1:
item_iter = repeat_last(items)
return [self.get(obj, level-1, next(item_iter), f) for obj in data]
elif level:
return [self.get(obj, level-1, items, f) for obj in data]
else:
return f(data, items)
def register():
bpy.utils.register_class(ListItem2Node)
def unregister():
bpy.utils.unregister_class(ListItem2Node)
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать