Esempio n. 1
0
    def draw_buttons(self, ctx, layout):

        layout.prop(self,
                    'current_op',
                    text="",
                    icon_value=custom_icon("SV_FUNCTION"))
        layout.prop(self, 'clamp_output')
Esempio n. 2
0
def layout_draw_categories(layout, node_details):

    for node_info in node_details:

        if node_info[0] == 'separator':
            layout.separator()
            continue

        if not node_info:
            print(repr(node_info), 'is incomplete, or unparsable')
            continue

        bl_idname = node_info[0]

        # this is a node bl_idname that can be registered but shift+A can drop it from showing.
        if bl_idname == 'ScalarMathNode':
            continue

        node_ref = get_node_class_reference(bl_idname)

        if hasattr(node_ref, "bl_label"):
            layout_params = dict(text=node_ref.bl_label, **node_icon(node_ref))
        elif bl_idname == 'NodeReroute':
            layout_params = dict(text='Reroute',icon_value=custom_icon('SV_REROUTE'))
        else:
            continue

        node_op = draw_add_node_operator(layout, bl_idname, params=layout_params)
Esempio n. 3
0
 def draw_buttons_ext(self, ctx, layout):
     layout.row().prop(self, "current_op", text="", icon_value=custom_icon("SV_FUNCTION"))
     layout.row().prop(self, 'input_mode_one', text="input 1")
     if len(self.inputs) == 2:
         layout.row().prop(self, 'input_mode_two', text="input 2")
     if self.current_op not in ['GCD', 'ROUND-N']:
         layout.row().prop(self, 'list_match', expand=False)
         layout.prop(self, "output_numpy", expand=False)
Esempio n. 4
0
 def draw_buttons(self, ctx, layout):
     row = layout.row(align=True)
     row.prop(self,
              "current_op",
              text="",
              icon_value=custom_icon("SV_FUNCTION"))
     if self.current_op == 'to_string':
         layout.prop(self, 'level')
Esempio n. 5
0
 def draw_buttons_ext(self, ctx, layout):
     layout.row().prop(self,
                       "current_op",
                       text="",
                       icon_value=custom_icon("SV_FUNCTION"))
     layout.row().prop(self, 'input_mode_one', text="input 1")
     if len(self.inputs) == 2:
         layout.row().prop(self, 'input_mode_two', text="input 2")
Esempio n. 6
0
 def draw_buttons_ext(self, ctx, layout):
     layout.prop(self,
                 'current_op',
                 text="",
                 icon_value=custom_icon("SV_FUNCTION"))
     layout.prop(self, 'list_match', expand=False)
     layout.prop(self, 'clamp_output')
     layout.prop(self, 'output_numpy', expand=False)
Esempio n. 7
0
def icon(display_icon):
    '''returns empty dict if show_icons is False, else the icon passed'''
    kws = {}
    if menu_prefs.get('show_icons'):
        if display_icon.startswith('SV_'):
            kws = {'icon_value': custom_icon(display_icon)}
        else: 
            kws = {'icon': display_icon}
    return kws
Esempio n. 8
0
def icon(display_icon):
    '''returns empty dict if show_icons is False, else the icon passed'''
    kws = {}
    if menu_prefs.get('show_icons'):
        if display_icon.startswith('SV_'):
            kws = {'icon_value': custom_icon(display_icon)}
        else: 
            kws = {'icon': display_icon}
    return kws
Esempio n. 9
0
 def draw_buttons_ext(self, ctx, layout):
     layout.prop(self,
                 "current_op",
                 text="",
                 icon_value=custom_icon("SV_FUNCTION"))
     layout.label(text="Implementation:")
     layout.prop(self, "implementation", expand=True)
     if self.implementation == "NumPy":
         layout.prop(self, "output_numpy", toggle=False)
 def draw_buttons_ext(self, ctx, layout):
     layout.row().prop(self,
                       "current_op",
                       text="",
                       icon_value=custom_icon("SV_FUNCTION"))
     layout.label(text="Wave interpolation options:")
     if self.current_op == 'Custom':
         layout.row().prop(self, "wave_interp_mode", expand=True)
         layout.row().prop(self, "knot_mode", expand=False)
     layout.prop(self, "list_match", expand=False)
     layout.prop(self, "output_numpy", expand=False)
Esempio n. 11
0
def node_icon(node_ref):
    '''returns empty dict if show_icons is False, else the icon passed'''
    if not menu_prefs.get('show_icons'):
        return {}
    else:
        if hasattr(node_ref, 'sv_icon'):
            iconID = custom_icon(node_ref.sv_icon)
            return {'icon_value': iconID} if iconID else {}
        elif hasattr(node_ref, 'bl_icon') and node_ref.bl_icon != 'OUTLINER_OB_EMPTY':
            iconID = node_ref.bl_icon
            return {'icon': iconID} if iconID else {}
        else:
            return {}
Esempio n. 12
0
def node_icon(node_ref):
    '''returns empty dict if show_icons is False, else the icon passed'''
    if not menu_prefs.get('show_icons'):
        return {}
    else:
        if hasattr(node_ref, 'sv_icon'):
            iconID = custom_icon(node_ref.sv_icon)
            return {'icon_value': iconID} if iconID else {}
        elif hasattr(node_ref, 'bl_icon') and node_ref.bl_icon != 'OUTLINER_OB_EMPTY':
            iconID = node_ref.bl_icon
            return {'icon': iconID} if iconID else {}
        else:
            return {}
Esempio n. 13
0
    def draw_buttons(self, context, layout):
        layout.row(align=True).prop(self, "mode", expand=True)
        col = layout.column(align=True)
        row = col.row(align=True)
        row.label(text='Instancer')
        row.prop(
            self,
            'show_instancer_for_viewport',
            text='',
            toggle=True,
            icon=
            f"RESTRICT_VIEW_{'OFF' if self.show_instancer_for_viewport else 'ON'}"
        )
        row.prop(
            self,
            'show_instancer_for_render',
            text='',
            toggle=True,
            icon=
            f"RESTRICT_RENDER_{'OFF' if self.show_instancer_for_render else 'ON'}"
        )

        row = col.row(align=True)
        row.label(text='Child')
        row.prop(self,
                 'show_base_child',
                 text='',
                 toggle=True,
                 icon=f"HIDE_{'OFF' if self.show_base_child else 'ON'}")
        if self.mode == 'FACES':
            row.prop(self,
                     'scale',
                     text='',
                     icon_value=custom_icon('SV_SCALE'),
                     toggle=True)
        else:
            row.prop(self,
                     'align',
                     text='',
                     icon='MOD_NORMALEDIT',
                     toggle=True)

        row.prop(self, 'auto_release', text='', toggle=True, icon='UNLINKED')
        if self.mode == 'VERTS' and self.align:
            layout.prop(self, 'track')
            layout.prop(self, 'up')
Esempio n. 14
0
    def draw_buttons(self, context, layout):
        self.draw_viewer_properties(layout)
        layout.row(align=True).prop(self, "mode", expand=True)
        col = layout.column(align=True)

        if self.mode == 'FACES':
            row = col.row(align=True)
            row.label(text='Instancer')
            row.prop(
                self,
                'show_instancer_for_viewport',
                text='',
                toggle=True,
                icon=
                f"RESTRICT_VIEW_{'OFF' if self.show_instancer_for_viewport else 'ON'}"
            )
            row.prop(
                self,
                'show_instancer_for_render',
                text='',
                toggle=True,
                icon=
                f"RESTRICT_RENDER_{'OFF' if self.show_instancer_for_render else 'ON'}"
            )

        row = col.row(align=True)
        row.label(text='Child')
        row.prop(self,
                 'show_base_child',
                 text='',
                 toggle=True,
                 icon=f"HIDE_{'OFF' if self.show_base_child else 'ON'}")
        if self.mode == 'FACES':
            row.prop(self,
                     'scale',
                     text='',
                     icon_value=custom_icon('SV_SCALE'),
                     toggle=True)
        row.prop(self, 'auto_release', text='', toggle=True, icon='UNLINKED')
        row.prop(self,
                 'ignore_base_offset',
                 text='',
                 toggle=True,
                 icon='TRANSFORM_ORIGINS')
Esempio n. 15
0
def layout_draw_categories(layout, category_name, node_details):

    global menu_class_by_title

    for node_info in node_details:

        if node_info[0] == 'separator':
            layout.separator()
            continue

        if not node_info:
            print(repr(node_info), 'is incomplete, or unparsable')
            continue

        bl_idname = node_info[0]

        if is_submenu_call(bl_idname):
            submenu_title = get_submenu_call_name(bl_idname)
            menu_title = compose_submenu_name(category_name, bl_idname)
            menu_class = menu_class_by_title[menu_title]
            layout.menu(menu_class.__name__, text=submenu_title)
            continue

        # this is a node bl_idname that can be registered but shift+A can drop it from showing.
        if bl_idname == 'ScalarMathNode':
            continue

        node_ref = get_node_class_reference(bl_idname)

        if hasattr(node_ref, "bl_label"):
            layout_params = dict(text=node_ref.bl_label, **node_icon(node_ref))
        elif bl_idname == 'NodeReroute':
            layout_params = dict(text='Reroute',
                                 icon_value=custom_icon('SV_REROUTE'))
        else:
            continue

        node_op = draw_add_node_operator(layout,
                                         bl_idname,
                                         params=layout_params)
Esempio n. 16
0
 def draw_buttons(self, ctx, layout):
     row = layout.row(align=True)
     row.prop(self,
              "current_op",
              text="",
              icon_value=custom_icon("SV_FUNCTION"))
Esempio n. 17
0
#
# ##### END GPL LICENSE BLOCK #####
from math import radians
import bpy
from bpy.props import IntProperty, FloatProperty, BoolProperty, EnumProperty

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, list_match_func, list_match_modes, sv_zip
from sverchok.ui.sv_icons import custom_icon
from sverchok.utils.modules.vertex_utils import center, center_of_many
from sverchok.utils.listutils import lists_flat

from sverchok.utils.pentagon_geom import generate_penta_grid, generate_penta_tiles, pentagon_dict

GRID_TYPE_ITEMS = [
    ("PENTAGON1", "Type 1 2-tile", "", custom_icon("SV_PENTAGON_1_1"), 2),
    ("TYPE_1_4", "Type 1 4-tile", "", custom_icon("SV_PENTAGON_1_2"), 3),
    ("PENTAGON2", "Type 1 2-tile X", "", custom_icon("SV_PENTAGON_1_3"), 4),
    ("PENTAGON3", "Type 1 2-tile 2", "", custom_icon("SV_PENTAGON_1_4"), 5),
    ("TYPE_2_1", "Type 2_1", "", custom_icon("SV_PENTAGON_2"), 7),
    ("PENTAGON_TYPE_3", "Type 3 3-tile", "", custom_icon("SV_PENTAGON_3"), 8),
    ("PENTAGON_TYPE_4", "Type 4 4-tile", "", custom_icon("SV_PENTAGON_4"), 9),
    ("PENTAGON_TYPE_5", "Type 5 6-tile", "", custom_icon("SV_PENTAGON_5"), 10),
    ("PENTAGON14", "Type 14", "", custom_icon("SV_PENTAGON_14"), 14),
    ("PENTAGON15", "Type 15", "", custom_icon("SV_PENTAGON_15"), 15)
]

ALIGN_ITEMS = [("X", "X", "Align tile primitives to X axis",
                custom_icon("SV_PENTAGON_X_ROT"), 0),
               ("Y", "Y", "Align tile primitives to Y axis",
                custom_icon("SV_PENTAGON_Y_ROT"), 1),
Esempio n. 18
0
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.props import IntProperty, FloatProperty, BoolProperty, EnumProperty

from math import sqrt, sin, cos, radians

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat
from sverchok.ui.sv_icons import custom_icon
from sverchok.utils.geom import circle
from sverchok.utils.sv_mesh_utils import mesh_join
from sverchok.nodes.modifier_change.remove_doubles import remove_doubles

grid_layout_items = [
    ("RECTANGLE", "Rectangle", "", custom_icon("SV_HEXA_GRID_RECTANGLE"), 0),
    ("TRIANGLE", "Triangle", "", custom_icon("SV_HEXA_GRID_TRIANGLE"), 1),
    ("DIAMOND", "Diamond", "", custom_icon("SV_HEXA_GRID_DIAMOND"), 2),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXA_GRID_HEXAGON"), 3)]
grid_type_items = [
    ("TRIANGLE", "Triangle", "", custom_icon("SV_TRIANGLE"), 0),
    ("SQUARE", "Square", "", custom_icon("SV_SQUARE"), 1),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXAGON"), 2)]
size_mode_items = [
    ("RADIUS", "Radius", "Define polygon by its radius", custom_icon("SV_RAD"), 0),
    ("SIDE", "Side", "Define polygon by its side", custom_icon("SV_SIDE"), 1)]


def triang_layout(settings, pol_type):
    '''Define triangular layout'''
    _, _, level = settings
class SvTriangleNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: from vertices, sides or angles
    Tooltip:  create triangle from various combinations of vertices, sides length and angles

    """

    bl_idname = "SvTriangleNode"
    bl_label = "Triangle"
    bl_icon = "GHOST_ENABLED"
    sv_icon = "SV_TRIANGLE_NODE"
    triangle_modes = [
        ("A_c_Alpha_Beta", "A_c_Alpha_Beta", "",
         custom_icon("SV_TRIANGLE_ACALPHABETA"), 0),
        ("A_Bv_Alpha_Beta", "A_B_Alpha_Beta", "",
         custom_icon("SV_TRIANGLE_ABALPHABETA"), 1),
        ("A_b_c_Alpha", "A_b_c_Alpha", "", custom_icon("SV_TRIANGLE_ABCALPHA"),
         2),
        ("A_Bv_b_Alpha", "A_B_b_Alpha", "",
         custom_icon("SV_TRIANGLE_ABBALPHA"), 3),
        ("A_as_b_c", "A_a_b_c", "", custom_icon("SV_TRIANGLE_AABC"), 4),
        ("A_Bv_as_b", "A_B_a_b", "", custom_icon("SV_TRIANGLE_ABAB"), 5),
        ("A_Bv_C", "A_B_C", "", custom_icon("SV_TRIANGLE_ABC"), 6)
    ]
    angle_units = [("Degrees", "Degrees", "", 0),
                   ("Radians", "Radians", "", 1)]

    def update_sokets(self, context):
        si = self.inputs
        inputs = ['A', 'Bv', 'C', 'as', 'b', 'c', 'Alpha', 'Beta']
        for idx, i in enumerate(inputs):
            if i in self.mode:
                if si[idx].hide_safe:
                    si[idx].hide_safe = False
            else:
                si[idx].hide_safe = True
        updateNode(self, context)

    mode: EnumProperty(name="Mode",
                       items=triangle_modes,
                       default="A_Bv_C",
                       update=update_sokets)
    angle_mode: EnumProperty(name="Angle Mode",
                             items=angle_units,
                             default="Degrees",
                             update=update_sokets)

    v3_input_0: FloatVectorProperty(name='A',
                                    description='Vertice A of triangle',
                                    size=3,
                                    default=(0, 0, 0),
                                    update=updateNode)
    v3_input_1: FloatVectorProperty(name='B',
                                    description='Vertice B of triangle',
                                    size=3,
                                    default=(0.5, 0.5, 0),
                                    update=updateNode)
    v3_input_2: FloatVectorProperty(name='C',
                                    description='Vertice C of triangle',
                                    size=3,
                                    default=(1, 0, 0),
                                    update=updateNode)

    size_a: FloatProperty(name='a',
                          description='Size side a',
                          default=10.0,
                          update=updateNode)
    size_b: FloatProperty(name='b',
                          description='Size side b',
                          default=10.0,
                          update=updateNode)
    size_c: FloatProperty(name='c',
                          description='Size side c',
                          default=10.0,
                          update=updateNode)

    alpha: FloatProperty(name='Alpha',
                         description='Angle at vertice A',
                         default=30.0,
                         update=updateNode)
    beta: FloatProperty(name='Beta',
                        description='Angle at vertice B',
                        default=30.0,
                        update=updateNode)

    list_match_global: EnumProperty(
        name="Match Global",
        description=
        "Behavior on different list lengths, multiple objects level",
        items=list_match_modes,
        default="REPEAT",
        update=updateNode)
    list_match_local: EnumProperty(
        name="Match Local",
        description="Behavior on different list lengths, object level",
        items=list_match_modes,
        default="REPEAT",
        update=updateNode)
    join_level: BoolProperty(
        name="Join Last level",
        description="Join (mesh join) last level of triangles",
        default=False,
        update=updateNode)
    flat_output: BoolProperty(
        name="Flat output",
        description="Flatten output by list-joining level 1",
        default=True,
        update=updateNode)
    rm_doubles: BoolProperty(
        name="Remove Doubles",
        description="Remove doubles of the joined triangles",
        default=True,
        update=updateNode)
    epsilon: FloatProperty(name='Tolerance',
                           description='Removing Doubles Tolerance',
                           default=1e-6,
                           update=updateNode)

    def draw_buttons(self, context, layout):
        layout.prop(self, "mode", expand=False)

    def draw_buttons_ext(self, context, layout):
        '''draw buttons on the N-panel'''

        layout.prop(self, "mode", expand=False)
        layout.prop(self, "angle_mode", expand=False)

        layout.separator()
        layout.prop(self, "join_level", text="Join Last Level", expand=False)
        if self.join_level:
            layout.prop(self, "rm_doubles", expand=False)
            if self.rm_doubles:
                layout.prop(self,
                            "epsilon",
                            text="Merge Distance",
                            expand=False)
        layout.prop(self, "flat_output", text="Flat Output", expand=False)
        layout.separator()
        layout.label(text="List Match:")
        layout.prop(self,
                    "list_match_global",
                    text="Global Match",
                    expand=False)
        layout.prop(self, "list_match_local", text="Local Match", expand=False)

    def rclick_menu(self, context, layout):
        '''right click sv_menu items'''
        layout.prop_menu_enum(self, "mode", text="Mode")
        layout.prop_menu_enum(self, "angle_mode", text="Angle Units")
        layout.separator()
        layout.prop(self, "join_level", text="Join Last Level", expand=False)
        if self.join_level:
            layout.prop(self, "rm_doubles", expand=False)
            if self.rm_doubles:
                layout.prop(self,
                            "epsilon",
                            text="Merge Distance",
                            expand=False)
        layout.prop(self, "flat_output", text="Flat Output", expand=False)
        layout.prop_menu_enum(self,
                              "list_match_global",
                              text="List Match Global")
        layout.prop_menu_enum(self,
                              "list_match_local",
                              text="List Match Local")

    def sv_init(self, context):
        sinw = self.inputs.new
        sinw('SvVerticesSocket', "A").prop_name = "v3_input_0"
        sinw('SvVerticesSocket', "B").prop_name = "v3_input_1"
        sinw('SvVerticesSocket', "C").prop_name = "v3_input_2"
        sinw('SvStringsSocket', "a").prop_name = "size_a"
        sinw('SvStringsSocket', "b").prop_name = "size_b"
        sinw('SvStringsSocket', "c").prop_name = "size_c"

        sinw('SvStringsSocket', "Alpha").prop_name = "alpha"
        sinw('SvStringsSocket', "Beta").prop_name = "beta"

        self.outputs.new('SvVerticesSocket', "Vertices")
        self.outputs.new('SvStringsSocket', "Edges")
        self.outputs.new('SvStringsSocket', "Faces")

    def main_func(self, params):
        out_verts, out_edges, out_faces = [], [], []
        for A, B, C, a, b, c, alpha, beta in zip(*params):
            if self.angle_mode == 'Degrees':
                alpha = radians(alpha)
                beta = radians(beta)
            if self.mode == 'A_Bv_C':
                verts = [A, B, C]
            if self.mode == 'A_c_Alpha_Beta':
                verts = triang_A_c_Alpha_Beta(A, c, alpha, beta)
            elif self.mode == 'A_Bv_Alpha_Beta':
                verts = triang_A_B_Alpha_Beta(A, B, alpha, beta)
            elif self.mode == 'A_Bv_as_b':
                verts = triang_A_B_a_b(A, B, a, b)
            elif self.mode == 'A_as_b_c':
                verts = triang_A_a_b_c(A, a, b, c)
            elif self.mode == 'A_b_c_Alpha':
                verts = triang_A_b_c_Alpha(A, b, c, alpha)
            elif self.mode == 'A_Bv_b_Alpha':
                verts = triang_A_B_b_Alpha(A, B, b, alpha)

            out_verts.append(verts)
            out_edges.append([[0, 1], [1, 2], [2, 0]])
            out_faces.append([[0, 1, 2]])

        if self.join_level:
            out_verts, out_edges, out_faces = mesh_join(
                out_verts, out_edges, out_faces)
            if self.rm_doubles:
                out_verts, out_edges, out_faces = remove_doubles(
                    out_verts, out_edges, out_faces, self.epsilon)

            out_verts, out_edges, out_faces = [out_verts], [out_edges
                                                            ], [out_faces]
        return out_verts, out_edges, out_faces

    def process(self):
        # return if no outputs are connected
        if not any(s.is_linked for s in self.outputs):
            return

        out_verts = []
        out_edges = []
        out_faces = []

        match_func = list_match_func[self.list_match_global]
        family = match_func([si.sv_get(default=[[]]) for si in self.inputs])
        for params in zip(*family):
            match_func = list_match_func[self.list_match_local]
            params = match_func(params)
            verts, edges, faces = self.main_func(params)

            out_verts.append(verts)
            out_edges.append(edges)
            out_faces.append(faces)

        if self.flat_output:
            out_verts, out_edges, out_faces = lists_flat(
                [out_verts, out_edges, out_faces])

        self.outputs['Vertices'].sv_set(out_verts)
        self.outputs['Edges'].sv_set(out_edges)
        self.outputs['Faces'].sv_set(out_faces)
Esempio n. 20
0
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.props import IntProperty, FloatProperty, BoolProperty, EnumProperty

from math import sqrt, sin, cos, radians

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat
from sverchok.ui.sv_icons import custom_icon
from sverchok.utils.geom import circle
from sverchok.utils.sv_mesh_utils import mesh_join
from sverchok.utils.sv_bmesh_utils import remove_doubles

grid_layout_items = [
    ("RECTANGLE", "Rectangle", "", custom_icon("SV_HEXA_GRID_RECTANGLE"), 0),
    ("TRIANGLE", "Triangle", "", custom_icon("SV_HEXA_GRID_TRIANGLE"), 1),
    ("DIAMOND", "Diamond", "", custom_icon("SV_HEXA_GRID_DIAMOND"), 2),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXA_GRID_HEXAGON"), 3)]
grid_type_items = [
    ("TRIANGLE", "Triangle", "", custom_icon("SV_TRIANGLE"), 0),
    ("SQUARE", "Square", "", custom_icon("SV_SQUARE"), 1),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXAGON"), 2)]
size_mode_items = [
    ("RADIUS", "Radius", "Define polygon by its radius", custom_icon("SV_RAD"), 0),
    ("SIDE", "Side", "Define polygon by its side", custom_icon("SV_SIDE"), 1)]


def triang_layout(settings, pol_type):
    '''Define triangular layout'''
    _, _, level = settings
Esempio n. 21
0
 def draw_buttons(self, ctx, layout):
     layout.prop(self, "current_op", text="", icon_value=custom_icon("SV_FUNCTION"))
#
# ##### END GPL LICENSE BLOCK #####

from math import pi
import bpy
from bpy.props import EnumProperty, FloatProperty, BoolProperty

from sverchok.ui.sv_icons import custom_icon
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, list_match_func, list_match_modes, numpy_list_match_modes, numpy_list_match_func
from sverchok.utils.sv_itertools import (recurse_f_level_control)
from sverchok.utils.geom import LinearSpline, CubicSpline
import numpy as np

mode_Items = [
    ("Sine", "Sine", "Sinusoidal wave", custom_icon("SV_OSCILLATOR_SINE"), 0),
    ("Square", "Square", "Square wave", custom_icon("SV_OSCILLATOR_INT"), 1),
    ("Saw", "Saw", "Saw wave", custom_icon("SV_OSCILLATOR_SAW"), 2),
    ("Triangular", "Triangle", "Triangular", custom_icon("SV_OSCILLATOR_TRI"),
     3),
    ("Custom", "Custom", "Custom wave", custom_icon("SV_OSCILLATOR_WAVE"), 4),
]


def oscillator(params, constant, matching_f):
    result = []
    mode, spline_func, knots, match_mode, out_numpy = constant
    params = matching_f(params)
    numpy_match = numpy_list_match_func[match_mode]
    for props in zip(*params):
        wave = props[5]
Esempio n. 23
0
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.props import IntProperty, FloatProperty, BoolProperty, EnumProperty

from math import sqrt, sin, cos, radians

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat
from sverchok.ui.sv_icons import custom_icon
from sverchok.utils.geom import circle
from sverchok.utils.sv_mesh_utils import mesh_join
from sverchok.nodes.modifier_change.remove_doubles import remove_doubles

grid_layout_items = [
    ("RECTANGLE", "Rectangle", "", custom_icon("SV_HEXA_GRID_RECTANGLE"), 0),
    ("TRIANGLE", "Triangle", "", custom_icon("SV_HEXA_GRID_TRIANGLE"), 1),
    ("DIAMOND", "Diamond", "", custom_icon("SV_HEXA_GRID_DIAMOND"), 2),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXA_GRID_HEXAGON"), 3)
]
grid_type_items = [("TRIANGLE", "Triangle", "", custom_icon("SV_TRIANGLE"), 0),
                   ("SQUARE", "Square", "", custom_icon("SV_SQUARE"), 1),
                   ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXAGON"), 2)]
size_mode_items = [("RADIUS", "Radius", "Define polygon by its radius",
                    custom_icon("SV_RAD"), 0),
                   ("SIDE", "Side", "Define polygon by its side",
                    custom_icon("SV_SIDE"), 1)]


def triang_layout(settings, pol_type):
    '''Define triangular layout'''
Esempio n. 24
0
class SvAdaptivePolygonsNodeMk2(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Adaptive Polygons Tessellate Tissue
    Tooltip: Generate an adapted copy of donor object along each face of recipient object.
    """
    bl_idname = 'SvAdaptivePolygonsNodeMk2'
    bl_label = 'Adaptive Polygons Mk2'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_ADAPTATIVE_POLS'

    axes = [
            ("X", "X", "Orient donor's X axis along normal", 0),
            ("Y", "Y", "Orient donor's Y axis along normal", 1),
            ("Z", "Z", "Orient donor's Z axis along normal", 2)
        ]

    normal_axis: EnumProperty(
        name = "Normal axis",
        description = "Donor object axis to be oriented along recipient face normal",
        items = axes,
        default = 'Z',
        update = updateNode)

    width_coef: FloatProperty(
        name='Width coeff',
        description = "Donor object width coefficient",
        default=1.0, max=3.0, min=0.5, update=updateNode)
    
    frame_width: FloatProperty(
        name='Frame width',
        description = "Frame width coefficient for Frame / Fan mode",
        default=0.5, max=1.0, min=0.0, update=updateNode)
    
    z_coef: FloatProperty(
        name='Z coeff',
        default=1.0, max=3.0, min=0.0, update=updateNode)

    z_offset: FloatProperty(
        name = "Z offet",
        default = 0.0,
        update = updateNode)

    normal_interp_modes = [
            ("LINEAR", "Linear", "Exact / linear normals interpolation", 0),
            ("SMOOTH", "Unit length", "Use normals of unit length", 1)
        ]

    normal_interp_mode : EnumProperty(
        name = "Interpolate normals",
        description = "Normals interpolation mode",
        items = normal_interp_modes, default = "LINEAR",
        update = updateNode)

    normal_modes = [
            ("MAP", "Map", "Interpolate from donor vertex normals", 0),
            ("FACE", "Face", "Use donor face normals", 1)
        ]

    normal_mode : EnumProperty(
        name = "Use normals",
        description = "Normals mapping mode",
        items = normal_modes, default = "MAP",
        update = updateNode)

    use_shell_factor : BoolProperty(
        name = "Use shell factor",
        description = "Use shell factor to make shell thickness constant",
        default = False,
        update = updateNode)
    
    z_scale_modes = [
            ("PROP", "Proportional", "Scale along normal proportionally with the donor object", 0),
            ("CONST", "Constant", "Constant scale along normal", 1),
            ("AUTO", "Auto", "Try to calculate the correct scale automatically", 2)
        ]

    z_scale : EnumProperty(
        name = "Z Scale",
        description = "Mode of scaling along the normals",
        items = z_scale_modes, default = "PROP",
        update = updateNode)

    z_rotation: FloatProperty(
        name = "Z Rotation",
        description = "Rotate donor object around recipient's face normal",
        min = 0, max = 2*pi, default = 0,
        update = updateNode)
    
    poly_rotation: IntProperty(
        name = "Polygons rotation",
        description = "Rotate indexes in polygons definition",
        min = 0, default = 0,
        update = updateNode)

    xy_modes = [
            ("BOUNDS", "Bounds", "Map donor object bounds to recipient face", 0),
            ("PLAIN", "As Is", "Map donor object's coordinate space to recipient face as-is", 1)
        ]

    xy_mode : EnumProperty(
        name = "Coordinates",
        description = "Donor object coordinates mapping",
        items = xy_modes, default = "BOUNDS",
        update = updateNode)

    tri_bound_modes = [
            ("EQUILATERAL", "Equilateral", "Use unit-sided equilateral triangle as a base area",
                custom_icon("SV_EQUILATERAL_TRIANGLE"), 0),
            ("RECTANGULAR", "Rectangular", "Use rectangular triangle with hypotenuse of 2 as a base area",
                custom_icon("SV_RECTANGULAR_TRIANGLE"), 1)
        ]

    tri_bound_mode : EnumProperty(
        name = "Bounding triangle",
        description = "Type of triangle to use as a bounding triangle",
        items = tri_bound_modes,
        default = "EQUILATERAL",
        update = updateNode)

    map_modes = [
            ("QUADTRI", "Quads / Tris Auto", "Use Quads or Tris mapping automatically", 0),
            ("QUADS", "Quads Always", "Use Quads mapping even for the Tris", 1)
        ]

    map_mode : EnumProperty(
        name = "Faces mode",
        description = "Donor object mapping mode",
        items = map_modes, default = "QUADTRI",
        update = updateNode)

    skip_modes = [
            ("SKIP", "Skip", "Do not output anything", 0),
            ("ASIS", "As Is", "Output these faces as is", 1)
        ]

    mask_mode: EnumProperty(
        name = "Mask mode",
        description = "What to do with masked out faces",
        items = skip_modes, default = "SKIP",
        update = updateNode)

    ngon_modes = [
            ("QUADS", "As Quads", "Try to process as Quads", 0),
            ("SKIP", "Skip", "Do not output anything", 1),
            ("ASIS", "As Is", "Output these faces as is", 2)
        ]

    ngon_mode: EnumProperty(
        name = "NGons",
        description = "What to do with NGons",
        items = ngon_modes, default = "QUADS",
        update = updateNode)

    @throttle_and_update_node
    def update_sockets(self, context):
        show_width = self.frame_mode != 'NEVER'
        if 'FrameWidth' in self.inputs:
            self.inputs['FrameWidth'].hide_safe = not show_width
        if 'Threshold' in self.inputs:
            self.inputs['Threshold'].hide_safe = not self.join or not self.remove_doubles

    frame_modes = [
            ("NEVER", "Do not use", "Do not use Frame / Fan mode", 0),
            ("NGONS", "NGons only", "Use Frame / Fan mode for NGons (n > 4) only", 1),
            ("NGONQUAD", "NGons and Quads", "Use Frame / Fan mode for NGons and Quads (n >= 4)", 2),
            ("ALWAYS", "Always", "Use Frame / Fan mode for all faces", 3)
        ]
    
    frame_mode: EnumProperty(
        name = "Frame mode",
        description = "When to use Frame / Fan mode",
        items = frame_modes, default = 'NEVER',
        update = update_sockets)

    matching_modes = [
            ("LONG", "Match longest", "Make an iteration for each donor or recipient object - depending on which list is longer", 0),
            ("PERFACE", "Donor per face", "If there are many donor objects, match each donor object with corresponding recipient object face", 1)
        ]

    matching_mode: EnumProperty(
        name = "Matching",
        description = "How to match list of recipient objects with list of donor objects",
        items = matching_modes, default = "LONG",
        update = updateNode)

    join : BoolProperty(
        name = "Join",
        description = "Output one joined mesh",
        default = False,
        update = updateNode)

    remove_doubles : BoolProperty(
        name = "Remove doubles",
        description = "Merge vertices at the same location",
        default = False,
        update = update_sockets)

    threshold : FloatProperty(
        name = "Threshold",
        description = "Threshold for vertices to be considered as identical",
        precision=4, min=0,
        default = 1e-4,
        update = updateNode)

    tri_vert_idxs = [0, 1, 2]
    quad_vert_idxs = [0, 1, 2, -1]

    def sv_init(self, context):
        self.inputs.new('SvVerticesSocket', "VersR")
        self.inputs.new('SvStringsSocket', "PolsR")
        self.inputs.new('SvVerticesSocket', "VersD")
        self.inputs.new('SvStringsSocket', "PolsD")
        self.inputs.new('SvStringsSocket', "FaceDataD")
        self.inputs.new('SvStringsSocket', "W_Coef").prop_name = 'width_coef'
        self.inputs.new('SvStringsSocket', "FrameWidth").prop_name = 'frame_width'
        self.inputs.new('SvStringsSocket', "Z_Coef").prop_name = 'z_coef'
        self.inputs.new('SvStringsSocket', "Z_Offset").prop_name = 'z_offset'
        self.inputs.new('SvStringsSocket', "Z_Rotation").prop_name = 'z_rotation'
        self.inputs.new('SvStringsSocket', "PolyRotation").prop_name = 'poly_rotation'
        self.inputs.new('SvStringsSocket', "PolyMask")
        self.inputs.new('SvStringsSocket', "Threshold").prop_name = 'threshold'

        self.outputs.new('SvVerticesSocket', "Vertices")
        self.outputs.new('SvStringsSocket', "Polygons")
        self.outputs.new('SvStringsSocket', "FaceData")
        self.outputs.new('SvStringsSocket', "VertRecptIdx")
        self.outputs.new('SvStringsSocket', "FaceRecptIdx")

        self.update_sockets(context)

    def draw_buttons(self, context, layout):
        layout.prop(self, "join")
        if self.join:
            layout.prop(self, "remove_doubles")
        layout.prop(self, "matching_mode")

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)

        layout.label(text = "Normal axis:")
        layout.prop(self, "normal_axis", expand=True)
        layout.prop(self, "z_scale")
        layout.prop(self, "normal_mode")
        if self.normal_mode == 'MAP':
            layout.prop(self, "normal_interp_mode")
        layout.prop(self, "use_shell_factor")
        layout.prop(self, "xy_mode")
        layout.label(text="Bounding triangle:")
        layout.prop(self, "tri_bound_mode", expand=True)
        layout.prop(self, "frame_mode")
        layout.prop(self, "map_mode")
        layout.prop(self, "mask_mode")
        layout.prop(self, "ngon_mode")

    def get_triangle_directions(self):
        """
        Three normal of unit triangle's edges.
        This is not constant just because the normal can be X or Y or Z.
        """
        if self.tri_bound_mode == 'EQUILATERAL':
            triangle_direction_1 = Vector((cos_pi_6, sin_pi_6, 0))
            triangle_direction_2 = Vector((-cos_pi_6, sin_pi_6, 0))
            triangle_direction_3 = Vector((0, -1, 0))
        else:
            triangle_direction_1 = Vector((1, 1, 0))
            triangle_direction_2 = Vector((-1, 1, 0))
            triangle_direction_3 = Vector((0, -1, 0))

        if self.normal_axis == 'X':
            return triangle_direction_1.zxy, triangle_direction_2.zxy, triangle_direction_3.zxy
        elif self.normal_axis == 'Y':
            return triangle_direction_1.xzy, triangle_direction_2.xzy, triangle_direction_3.xzy
        else:
            return triangle_direction_1, triangle_direction_2, triangle_direction_3

    def to2d(self, v):
        """
        Convert vector to 2D.
        Remove the coordinate which is responsible for normal axis.
        """
        if self.normal_axis == 'X':
            return v.yz
        elif self.normal_axis == 'Y':
            return v.xz
        else:
            return v.xy

    def from2d(self, x, y):
        """
        Make 3D vector from X and Y.
        Add zero for the coordinate which is responsible for normal axis.
        """
        if self.normal_axis == 'X':
            return Vector((0, x, y))
        elif self.normal_axis == 'Y':
            return Vector((x, 0, y))
        else:
            return Vector((x, y, 0))

    def bounding_triangle(self, vertices):
        """
        Return three vertices of a triangle with equal sides / rectangular triangle,
        which contains all provided vertices.
        """
        X, Y = self.get_other_axes()

        triangle_direction_1, triangle_direction_2, triangle_direction_3 = self.get_triangle_directions()
        max_1 = self.to2d(max(vertices, key = lambda vertex: triangle_direction_1.dot(vertex)))
        max_2 = self.to2d(max(vertices, key = lambda vertex: triangle_direction_2.dot(vertex)))
        max_3 = self.to2d(min(vertices, key = lambda vertex: vertex[Y]))

        side_1 = LineEquation2D.from_normal_and_point(self.to2d(triangle_direction_1), max_1)
        side_2 = LineEquation2D.from_normal_and_point(self.to2d(triangle_direction_2), max_2)
        side_3 = LineEquation2D.from_normal_and_point(self.to2d(triangle_direction_3), max_3)

        p1 = side_2.intersect_with_line(side_3)
        p2 = side_1.intersect_with_line(side_3)
        p3 = side_1.intersect_with_line(side_2)

        p1 = self.from2d(p1[0], p1[1])
        p2 = self.from2d(p2[0], p2[1])
        p3 = self.from2d(p3[0], p3[1])

        return p1, p2, p3

    def interpolate_quad_2d(self, dst_vert_1, dst_vert_2, dst_vert_3, dst_vert_4, v, x_coef, y_coef):
        """
        Map the provided `v` vertex, considering only two of it's coordinates,
        from the [-1/2; 1/2] x [-1/2; 1/2] square to the face defined by
        four `dst_vert_n` vertices.
        """
        X, Y = self.get_other_axes()
        v12 = dst_vert_1 + (dst_vert_2-dst_vert_1)*v[X]*x_coef + ((dst_vert_2-dst_vert_1)/2)
        v43 = dst_vert_4 + (dst_vert_3-dst_vert_4)*v[X]*x_coef + ((dst_vert_3-dst_vert_4)/2)
        return v12 + (v43-v12)*v[Y]*y_coef + ((v43-v12)/2)

    def interpolate_quad_3d(self, dst_vert_1, dst_vert_2, dst_vert_3, dst_vert_4, dst_normal_1, dst_normal_2, dst_normal_3, dst_normal_4, face_normal, v, x_coef, y_coef, z_coef, z_offset):
        """
        Map the provided `v` vertex from the source
        [-1/2; 1/2] x [-1/2; 1/2] x [-1/2; 1/2] cube
        to the space defined by `dst_vert_n` vertices.
        """
        loc = self.interpolate_quad_2d(dst_vert_1, dst_vert_2, dst_vert_3, dst_vert_4, v, x_coef, y_coef)
        if self.normal_mode == 'MAP':
            if self.normal_interp_mode == 'SMOOTH':
                normal = self.interpolate_quad_2d(dst_normal_1, dst_normal_2, dst_normal_3, dst_normal_4, v, x_coef, y_coef)
                normal.normalize()
            else:
                normal = self.interpolate_quad_2d(dst_vert_1 + dst_normal_1, dst_vert_2 + dst_normal_2,
                                             dst_vert_3 + dst_normal_3, dst_vert_4 + dst_normal_4,
                                             v, x_coef, y_coef)
                normal = normal - loc
        else:
            #normal = (dst_vert_1.normal + dst_vert_2.normal + dst_vert_3.normal + dst_vert_4.normal) * 0.25
            normal = face_normal
        Z = self.normal_axis_idx()
        return loc + normal*(v[Z]*z_coef + z_offset)

    def interpolate_tri_2d(self, dst_vert_1, dst_vert_2, dst_vert_3, src_vert_1, src_vert_2, src_vert_3, v):
        """
        Map the provided `v` vertex, considering only two of it's coordinates,
        from the source triangle (defined by `src_vert_n` vertices) to the face defined by
        three `dst_vert_n` vertices.
        """
        X, Y = self.get_other_axes()
        v = self.from2d(v[X], v[Y])
        return barycentric_transform(v, src_vert_1, src_vert_2, src_vert_3,
                                        dst_vert_1, dst_vert_2, dst_vert_3)

    def interpolate_tri_3d(self, dst_vert_1, dst_vert_2, dst_vert_3, dst_normal_1, dst_normal_2, dst_normal_3, src_vert_1, src_vert_2, src_vert_3, face_normal, v, z_coef, z_offset):
        """
        Map the provided `v` vertex from the source triangle
        to the space defined by `dst_vert_n` vertices.
        """
        v_at_triangle = self.interpolate_tri_2d(dst_vert_1, dst_vert_2, dst_vert_3,
                                            src_vert_1, src_vert_2, src_vert_3, v)
        if self.normal_mode == 'MAP':
            if self.normal_interp_mode == 'SMOOTH':
                normal = self.interpolate_tri_2d(dst_normal_1, dst_normal_2, dst_normal_3,
                                             src_vert_1, src_vert_2, src_vert_3, v)
                normal.normalize()
            else:
                normal = self.interpolate_tri_2d(dst_vert_1 + dst_normal_1, dst_vert_2 + dst_normal_2,
                                            dst_vert_3 + dst_normal_3,
                                            src_vert_1, src_vert_2, src_vert_3, v)
                normal = normal - v_at_triangle
        else:
            #normal = (dst_vert_1.normal + dst_vert_2.normal + dst_vert_3.normal) * 0.333333333
            normal = face_normal
        Z = self.normal_axis_idx()
        return v_at_triangle + normal * (v[Z] * z_coef + z_offset)

    def get_other_axes(self):
        if self.normal_axis == 'X':
            return 1, 2
        elif self.normal_axis == 'Y':
            return 0, 2
        else:
            return 0, 1

    def normal_axis_idx(self):
        return "XYZ".index(self.normal_axis)

    def map_bounds(self, min, max, x):
        c = (min + max) / 2.0
        k = 1.0 / (max - min)
        return (x - c) * k

    def rotate_z(self, verts, angle):
        if abs(angle) < 1e-6:
            return verts
        projection = [self.to2d(v) for v in verts]
        x0, y0 = center(projection)
        c = self.from2d(x0, y0)
        rot = Matrix.Rotation(angle, 4, self.normal_axis)
        result = [(rot @ (v - c)) + c for v in verts]
        return result

    def calc_z_scale(self, dst_verts, src_verts):
        src_lens = []
        for v1, v2 in zip(src_verts, src_verts[1:]):
            src_lens.append((v1 - v2).length)
        src_lens.append((src_verts[-1] - src_verts[0]).length)

        dst_lens = []
        for v1, v2 in zip(dst_verts, dst_verts[1:]):
            dst_lens.append((v1 - v2).length)
        dst_lens.append((dst_verts[-1] - dst_verts[0]).length)

        scales = [dst_len / src_len for src_len,dst_len in zip(src_lens, dst_lens) if abs(src_len) > 1e-6 and abs(dst_len) > 1e-6]
        n = len(scales)
        prod = reduce(lambda x,y: x*y, scales, 1.0)
        return pow(prod, 1.0/n)

    def _process_face(self, map_mode, output, recpt_face_data, donor, zcoef, zoffset, angle, wcoef, facerot):

        X, Y = self.get_other_axes()
        Z = self.normal_axis_idx()
        #self.info(f"Face: {len(recpt_face_data.vertices_co)}, mode: {map_mode}")

        if map_mode == 'ASIS':
            # Leave this recipient's face as it was - as a single face.
            verts = recpt_face_data.vertices_co[:]
            n = len(verts)
            output.verts_out.append(verts)
            output.faces_out.append([list(range(n))])
            output.vert_recpt_idx_out.append([recpt_face_data.index for i in verts])
            output.face_recpt_idx_out.append([recpt_face_data.index for i in range(n)])

        elif map_mode == 'TRI':
            # Tris processing mode.
            #
            # As interpolate_tri_3d is based on barycentric_transform,
            # here we do not have to manually map donor vertices to the
            # unit triangle.

            i0, i1, i2 = rotate_list(self.tri_vert_idxs, facerot)
            if self.z_scale == 'AUTO':
                zcoef = self.calc_z_scale(
                                    [recpt_face_data.vertices_co[i0],
                                     recpt_face_data.vertices_co[i1],
                                     recpt_face_data.vertices_co[i2]],
                                    [donor.tri_vert_1/wcoef, donor.tri_vert_2/wcoef, donor.tri_vert_3/wcoef]
                                ) * zcoef
            new_verts = []
            for v in donor.verts_v:
                new_verts.append(self.interpolate_tri_3d(
                                    recpt_face_data.vertices_co[i0],
                                    recpt_face_data.vertices_co[i1],
                                    recpt_face_data.vertices_co[i2],
                                    recpt_face_data.vertices_normal[i0],
                                    recpt_face_data.vertices_normal[i1],
                                    recpt_face_data.vertices_normal[i2],
                                    donor.tri_vert_1/wcoef, donor.tri_vert_2/wcoef, donor.tri_vert_3/wcoef,
                                    recpt_face_data.normal,
                                    v, zcoef, zoffset))
            output.verts_out.append(new_verts)
            output.faces_out.append(donor.faces_i)
            output.face_data_out.append(donor.face_data_i)
            output.vert_recpt_idx_out.append([recpt_face_data.index for i in new_verts])
            output.face_recpt_idx_out.append([recpt_face_data.index for i in donor.faces_i])

        elif map_mode == 'QUAD':
            # Quads processing mode.
            #
            # It can process Tris, but it will look strange:
            # triangle will be processed as degenerated Quad,
            # where third and fourth vertices coincide.
            # In Tissue addon, this is the only mode possible for Quads.
            # Someone may like that behaivour, so we allow it with setting...
            #
            # This can process NGons in even worse way:
            # it will take first three vertices and the last one
            # and consider that as a Quad.

            i0, i1, i2, i3 = rotate_list(self.quad_vert_idxs, facerot)
            if self.z_scale == 'AUTO':
                corner1 = self.from2d(donor.min_x, donor.min_y)
                corner2 = self.from2d(donor.min_x, donor.max_y)
                corner3 = self.from2d(donor.max_x, donor.max_y)
                corner4 = self.from2d(donor.max_x, donor.min_y)

                zcoef = self.calc_z_scale(
                                [recpt_face_data.vertices_co[i0],
                                 recpt_face_data.vertices_co[i1],
                                 recpt_face_data.vertices_co[i2],
                                 recpt_face_data.vertices_co[i3]],
                                [corner1, corner2, corner3, corner4]
                            ) * zcoef

            new_verts = []
            #self.info("Donor: %s", len(donor.verts_v))
            for v in donor.verts_v:
                if self.xy_mode == 'BOUNDS':
                    # Map the `v` vertex's X, Y coordinates
                    # from it's bounding square to
                    # [-1/2; 1/2] square.
                    # Leave Z coordinate as it was.
                    x = self.map_bounds(donor.min_x, donor.max_x, v[X])
                    y = self.map_bounds(donor.min_y, donor.max_y, v[Y])
                    z = v[Z]

                    v = Vector((0, 0, 0))
                    v[X] = x
                    v[Y] = y
                    v[Z] = z

                new_verts.append(self.interpolate_quad_3d(
                                    recpt_face_data.vertices_co[i0],
                                    recpt_face_data.vertices_co[i1],
                                    recpt_face_data.vertices_co[i2],
                                    recpt_face_data.vertices_co[i3],
                                    recpt_face_data.vertices_normal[i0],
                                    recpt_face_data.vertices_normal[i1],
                                    recpt_face_data.vertices_normal[i2],
                                    recpt_face_data.vertices_normal[i3],
                                    recpt_face_data.normal,
                                    v,
                                    wcoef, wcoef,
                                    zcoef, zoffset))

            output.verts_out.append(new_verts)
            output.faces_out.append(donor.faces_i)
            output.face_data_out.append(donor.face_data_i)
            output.vert_recpt_idx_out.append([recpt_face_data.index for i in new_verts])
            output.face_recpt_idx_out.append([recpt_face_data.index for i in donor.faces_i])

        elif map_mode == 'FRAME':
            is_fan = abs(recpt_face_data.frame_width - 1.0) < 1e-6
            n = len(recpt_face_data.vertices_co)
            if self.map_mode == 'QUADS':
                sub_map_mode = 'QUAD'
            else:
                if is_fan:
                    sub_map_mode = 'TRI'
                else:
                    sub_map_mode = 'QUAD'

            if is_fan:
                tri_faces = [(recpt_face_data.vertices_co[i],
                                recpt_face_data.vertices_co[i+1],
                                recpt_face_data.center) for i in range(n-1)]
                tri_faces.append((recpt_face_data.vertices_co[-1],
                                    recpt_face_data.vertices_co[0],
                                    recpt_face_data.center))

                if self.use_shell_factor:
                    face_normal = sum(recpt_face_data.vertices_normal, Vector()) / n
                else:
                    face_normal = recpt_face_data.normal
                tri_normals = [(recpt_face_data.vertices_normal[i],
                                recpt_face_data.vertices_normal[i+1],
                                face_normal) for i in range(n-1)]
                tri_normals.append((recpt_face_data.vertices_normal[-1],
                                    recpt_face_data.vertices_normal[0],
                                    face_normal))

                for tri_face, tri_normal in zip(tri_faces, tri_normals):
                    sub_recpt = recpt_face_data.copy()
                    sub_recpt.vertices_co = tri_face
                    sub_recpt.vertices_normal = tri_normal
                    sub_recpt.vertices_idxs = [0, 1, 2]
                    self._process_face(sub_map_mode, output, sub_recpt, donor, zcoef, zoffset, angle, wcoef, facerot)
            else:
                inner_verts = [vert.lerp(recpt_face_data.center, recpt_face_data.frame_width)
                                    for vert in recpt_face_data.vertices_co]
                if self.use_shell_factor:
                    inner_normals = [normal.lerp(recpt_face_data.normal, recpt_face_data.frame_width)
                                        for normal in recpt_face_data.vertices_normal]
                else:
                    face_normal = sum(recpt_face_data.vertices_normal, Vector()) / n
                    inner_normals = [normal.lerp(face_normal, recpt_face_data.frame_width)
                                        for normal in recpt_face_data.vertices_normal]

                quad_faces = [(recpt_face_data.vertices_co[i],
                                recpt_face_data.vertices_co[i+1],
                                inner_verts[i+1], inner_verts[i])
                                    for i in range(n-1)]
                quad_faces.append((recpt_face_data.vertices_co[-1],
                                    recpt_face_data.vertices_co[0],
                                    inner_verts[0], inner_verts[-1]))
                quad_normals = [(recpt_face_data.vertices_normal[i],
                                recpt_face_data.vertices_normal[i+1],
                                inner_normals[i+1], inner_normals[i])
                                    for i in range(n-1)]
                quad_normals.append((recpt_face_data.vertices_normal[-1],
                                    recpt_face_data.vertices_normal[0],
                                    inner_normals[0], inner_normals[-1]))

                for quad_face, quad_normal in zip(quad_faces, quad_normals):
                    sub_recpt = recpt_face_data.copy()
                    sub_recpt.vertices_co = quad_face
                    sub_recpt.vertices_normal = quad_normal
                    sub_recpt.vertices_idxs = [0, 1, 2, 3]
                    self._process_face(sub_map_mode, output, sub_recpt, donor, zcoef, zoffset, angle, wcoef, facerot)

    def _process(self, verts_recpt, faces_recpt, verts_donor, faces_donor, face_data_donor, frame_widths, zcoefs, zoffsets, zrotations, wcoefs, facerots, mask):
        bm = bmesh_from_pydata(verts_recpt, [], faces_recpt, normal_update=True)
        bm.verts.ensure_lookup_table()
        single_donor = self.matching_mode == 'LONG'
        frame_level = get_data_nesting_level(frame_widths)
        if single_donor:
            # Original (unrotated) donor vertices
            donor_verts_o = [Vector(v) for v in verts_donor]

            verts_donor = [verts_donor]
            faces_donor = [faces_donor]
            face_data_donor = [face_data_donor]
            if frame_level == 0:
                frame_widths = [frame_widths]

        n_faces_recpt = len(faces_recpt)
        fullList(verts_donor, n_faces_recpt)
        fullList(faces_donor, n_faces_recpt)
        fullList(face_data_donor, n_faces_recpt)
        fullList(frame_widths, n_faces_recpt)

        X, Y = self.get_other_axes()
        Z = self.normal_axis_idx()

        donor = DonorData()

        # Vertices of the unit triangle.
        # In case xy_mode != BOUNDS, we will never
        # have to recalculate these.
        if self.tri_bound_mode == 'EQUILATERAL':
            donor.tri_vert_1 = self.from2d(-0.5, -sqrt_3_6)
            donor.tri_vert_2 = self.from2d(0.5, -sqrt_3_6)
            donor.tri_vert_3 = self.from2d(0, sqrt_3_3)
        else:
            donor.tri_vert_1 = self.from2d(-1, 0)
            donor.tri_vert_2 = self.from2d(1, 0)
            donor.tri_vert_3 = self.from2d(0, 1)

        if single_donor:
            # We will be rotating the donor object around Z axis,
            # so it's size along Z is not going to change.
            z_size = diameter(donor_verts_o, Z)

        output = OutputData()

        prev_angle = None
        face_data = zip(faces_recpt, bm.faces, frame_widths, verts_donor, faces_donor, face_data_donor, zcoefs, zoffsets, zrotations, wcoefs, facerots, mask)
        recpt_face_idx = 0
        for recpt_face, recpt_face_bm, frame_width, donor_verts_i, donor_faces_i, donor_face_data_i, zcoef, zoffset, angle, wcoef, facerot, m in face_data:

            recpt_face_data = RecptFaceData()
            recpt_face_data.index = recpt_face_idx
            recpt_face_data.normal = recpt_face_bm.normal
            recpt_face_data.center = recpt_face_bm.calc_center_median()
            recpt_face_data.vertices_co = [bm.verts[i].co for i in recpt_face]
            if self.use_shell_factor:
                recpt_face_data.vertices_normal = [bm.verts[i].normal * bm.verts[i].calc_shell_factor() for i in recpt_face]
            else:
                recpt_face_data.vertices_normal = [bm.verts[i].normal for i in recpt_face]
            recpt_face_data.vertices_idxs = recpt_face[:]
            if not isinstance(frame_width, (int, float)):
                raise Exception(f"Unexpected data type for frame_width: {frame_width}")
            recpt_face_data.frame_width = frame_width

            donor.faces_i = donor_faces_i
            donor.face_data_i = donor_face_data_i

            if not single_donor:
                # Original (unrotated) donor vertices
                donor_verts_o = [Vector(v) for v in donor_verts_i]
                z_size = diameter(donor_verts_o, Z)

            # We have to recalculate rotated vertices only if
            # the rotation angle have changed.
            if prev_angle is None or angle != prev_angle or not single_donor:
                donor.verts_v = self.rotate_z(donor_verts_o, angle)

                if self.xy_mode == 'BOUNDS' or self.z_scale == 'AUTO' :
                    donor.max_x = max(v[X] for v in donor.verts_v)
                    donor.min_x = min(v[X] for v in donor.verts_v)
                    donor.max_y = max(v[Y] for v in donor.verts_v)
                    donor.min_y = min(v[Y] for v in donor.verts_v)

                if self.xy_mode == 'BOUNDS':
                    donor.tri_vert_1, donor.tri_vert_2, donor.tri_vert_3 = self.bounding_triangle(donor.verts_v)

            prev_angle = angle

            if self.z_scale == 'CONST':
                if abs(z_size) < 1e-6:
                    zcoef = 0
                else:
                    zcoef = zcoef / z_size

            # Define TRI/QUAD mode based on node settings.
            n = len(recpt_face)
            if not m:
                map_mode = self.mask_mode
            else:
                if n == 3:
                    if self.frame_mode == 'ALWAYS':
                        map_mode = 'FRAME'
                    else:
                        if self.map_mode == 'QUADTRI':
                            map_mode = 'TRI'
                        else: # self.map_mode == 'QUADS':
                            map_mode = 'QUAD'
                elif n == 4:
                    if self.frame_mode in ['ALWAYS', 'NGONQUAD']:
                        map_mode = 'FRAME'
                    else:
                        map_mode = 'QUAD'
                else:
                    if self.frame_mode in ['ALWAYS', 'NGONQUAD', 'NGONS']:
                        map_mode = 'FRAME'
                    else:
                        if self.ngon_mode == 'QUADS':
                            map_mode = 'QUAD'
                        elif self.ngon_mode == 'ASIS':
                            map_mode = 'ASIS'
                        else:
                            map_mode = 'SKIP'

            if map_mode == 'SKIP':
                # Skip this recipient's face - do not produce any vertices/faces for it
                continue

            self._process_face(map_mode, output, recpt_face_data, donor, zcoef, zoffset, angle, wcoef, facerot)
            recpt_face_idx += 1

        bm.free()

        return output

    def process(self):
        if not any(output.is_linked for output in self.outputs):
            return

        verts_recpt_s = self.inputs['VersR'].sv_get(deepcopy=False)
        faces_recpt_s = self.inputs['PolsR'].sv_get(default=[[]], deepcopy=False)
        verts_donor_s = self.inputs['VersD'].sv_get()
        faces_donor_s = self.inputs['PolsD'].sv_get()
        if 'FaceDataD' in self.inputs:
            face_data_donor_s = self.inputs['FaceDataD'].sv_get(default=[[]])
        else:
            face_data_donor_s = [[]]
        zcoefs_s = self.inputs['Z_Coef'].sv_get(deepcopy=False)
        zoffsets_s = self.inputs['Z_Offset'].sv_get(deepcopy=False)
        zrotations_s = self.inputs['Z_Rotation'].sv_get(deepcopy=False)
        wcoefs_s = self.inputs['W_Coef'].sv_get(deepcopy=False)
        if 'FrameWidth' in self.inputs:
            frame_widths_s = self.inputs['FrameWidth'].sv_get(deepcopy=True)
        else:
            frame_widths_s = [[0.5]]
        if 'PolyRotation' in self.inputs:
            facerots_s = self.inputs['PolyRotation'].sv_get(default = [[0]], deepcopy=False)
        else:
            facerots_s = [[0]]
        mask_s = self.inputs['PolyMask'].sv_get(default = [[1]], deepcopy=False)
        if 'Threshold' in self.inputs:
            thresholds_s = self.inputs['Threshold'].sv_get()
        else:
            thresholds_s = [[self.threshold]]

        output = OutputData()

        if self.matching_mode == 'PERFACE':
            verts_donor_s = [verts_donor_s]
            faces_donor_s = [faces_donor_s]
            face_data_donor_s = [face_data_donor_s]
            #self.info("FW: %s", frame_widths_s)
            #frame_widths_s = [frame_widths_s]
        objects = match_long_repeat([verts_recpt_s, faces_recpt_s, verts_donor_s, faces_donor_s, face_data_donor_s, frame_widths_s, zcoefs_s, zoffsets_s, zrotations_s, wcoefs_s, facerots_s, mask_s, thresholds_s])
        #self.info("N objects: %s", len(list(zip(*objects))))
        for verts_recpt, faces_recpt, verts_donor, faces_donor, face_data_donor, frame_widths, zcoefs, zoffsets, zrotations, wcoefs, facerots, mask, threshold in zip(*objects):
            n_faces_recpt = len(faces_recpt)
            fullList(zcoefs, n_faces_recpt)
            fullList(zoffsets, n_faces_recpt)
            fullList(zrotations, n_faces_recpt)
            if get_data_nesting_level(frame_widths) < 1:
                frame_widths = [frame_widths]
            fullList(frame_widths, n_faces_recpt)
            fullList(wcoefs, n_faces_recpt)
            fullList(facerots, n_faces_recpt)
            mask = cycle_for_length(mask, n_faces_recpt)

            if isinstance(threshold, (list, tuple)):
                threshold = threshold[0]

            new = self._process(verts_recpt, faces_recpt,
                                 verts_donor, faces_donor,
                                 face_data_donor,
                                 frame_widths,
                                 zcoefs, zoffsets, zrotations,
                                 wcoefs, facerots, mask)

            output.verts_out.extend(new.verts_out)
            output.faces_out.extend(new.faces_out)
            output.face_data_out.extend(new.face_data_out)
            output.vert_recpt_idx_out.extend(new.vert_recpt_idx_out)
            output.face_recpt_idx_out.extend(new.face_recpt_idx_out)

            output.verts_out = Vector_degenerate(output.verts_out)
            if self.join:
                output.verts_out, _, output.faces_out = mesh_join(output.verts_out, [], output.faces_out)
                output.face_data_out = sum(output.face_data_out, [])
                output.vert_recpt_idx_out = sum(output.vert_recpt_idx_out, [])
                output.face_recpt_idx_out = sum(output.face_recpt_idx_out, [])

                if self.remove_doubles:
                    doubles_res = remove_doubles(output.verts_out, [], output.faces_out, threshold, face_data=output.face_data_out, vert_data=output.vert_recpt_idx_out)
                    if len(doubles_res) == 4:
                        output.verts_out, _, output.faces_out, data_out = doubles_res
                    else:
                        output.verts_out, _, output.faces_out = doubles_res
                        data_out = dict()
                    output.vert_recpt_idx_out = data_out.get('verts', [])
                    if output.face_recpt_idx_out:
                        output.face_recpt_idx_out = [output.face_recpt_idx_out[idx] for idx in data_out['face_init_index']]

                output.verts_out = [output.verts_out]
                output.faces_out = [output.faces_out]
                output.face_data_out = [output.face_data_out]
                output.vert_recpt_idx_out = [output.vert_recpt_idx_out]
                output.face_recpt_idx_out = [output.face_recpt_idx_out]

            self.outputs['Vertices'].sv_set(output.verts_out)
            self.outputs['Polygons'].sv_set(output.faces_out)
            if 'FaceData' in self.outputs:
                self.outputs['FaceData'].sv_set(output.face_data_out)
            if 'VertRecptIdx' in self.outputs:
                self.outputs['VertRecptIdx'].sv_set(output.vert_recpt_idx_out)
            if 'FaceRecptIdx' in self.outputs:
                self.outputs['FaceRecptIdx'].sv_set(output.face_recpt_idx_out)
Esempio n. 25
0
#
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.props import IntProperty, FloatProperty, BoolProperty, EnumProperty

from math import sqrt, sin, cos, radians

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat
from sverchok.ui.sv_icons import custom_icon
from sverchok.utils.geom import circle
from sverchok.utils.sv_mesh_utils import mesh_join

gridLayoutItems = [
    ("RECTANGLE", "Rectangle", "", custom_icon("SV_HEXA_GRID_RECTANGLE"), 0),
    ("TRIANGLE", "Triangle", "", custom_icon("SV_HEXA_GRID_TRIANGLE"), 1),
    ("DIAMOND", "Diamond", "", custom_icon("SV_HEXA_GRID_DIAMOND"), 2),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXA_GRID_HEXAGON"), 3)
]


def generate_grid(center, layout, settings):
    r = settings[0]  # radius
    a = settings[1]  # angle

    dx = r * 3 / 2  # distance between two consecutive points along X
    dy = r * sqrt(3)  # distance between two consecutive points along Y
    '''
    X : number of points along X
    Y : number of points along Y for each X location
Esempio n. 26
0
 def draw_buttons(self, ctx, layout):
     layout.row().prop(self, "current_op", text="", icon_value=custom_icon("SV_FUNCTION"))
Esempio n. 27
0
#
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.props import IntProperty, FloatProperty, BoolProperty, EnumProperty

from math import sqrt, sin, cos, radians

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat
from sverchok.ui.sv_icons import custom_icon
from sverchok.utils.geom import circle
from sverchok.utils.sv_mesh_utils import mesh_join

gridLayoutItems = [
    ("RECTANGLE", "Rectangle", "", custom_icon("SV_HEXA_GRID_RECTANGLE"), 0),
    ("TRIANGLE", "Triangle", "", custom_icon("SV_HEXA_GRID_TRIANGLE"), 1),
    ("DIAMOND", "Diamond", "", custom_icon("SV_HEXA_GRID_DIAMOND"), 2),
    ("HEXAGON", "Hexagon", "", custom_icon("SV_HEXA_GRID_HEXAGON"), 3)]


def generate_grid(center, layout, settings):
    r = settings[0]   # radius
    a = settings[1]   # angle

    dx = r * 3 / 2    # distance between two consecutive points along X
    dy = r * sqrt(3)  # distance between two consecutive points along Y

    '''
    X : number of points along X
    Y : number of points along Y for each X location