diff --git a/docs/nodes/vector/vector_in.rst b/docs/nodes/vector/vector_in.rst index 492603c4a7cf72ee114b644b7012b0b5bb256075..90c6008f19ef225f1e62be4be3c18d47ed17490c 100644 --- a/docs/nodes/vector/vector_in.rst +++ b/docs/nodes/vector/vector_in.rst @@ -6,7 +6,7 @@ Functionality Inputs vector from ranges or number values either integer of floats. -With the NumPy implementation the node will accept regular lists or lists of NumPy arrays if the arrays have two axis arrays with shape [n,3] +With the NumPy implementation the node will accept regular lists or lists of flat NumPy arrays It can also output Numpy arrays (flat arrays) when using the activating the "Output NumPy" parameter. (See advanced parameters) diff --git a/docs/nodes/vector/vector_polar_in.rst b/docs/nodes/vector/vector_polar_in.rst index aa70d048a2f17c7c9270984e0a20dba04dd5903c..740f1773faaecf2498d352c8f70cd8d3dbf0c405 100644 --- a/docs/nodes/vector/vector_polar_in.rst +++ b/docs/nodes/vector/vector_polar_in.rst @@ -13,8 +13,10 @@ Inputs & Parameters All parameters except for ``Coordinates`` and ``Angles mode`` can be specified using corresponding inputs. +The node will accept regular lists or lists of flat NumPy arrays + +-----------------+---------------+-------------+----------------------------------------------------+ -| Parameter | Type | Default | Description | +| Parameter | Type | Default | Description | +=================+===============+=============+====================================================+ | **Coordinates** | Cylindrical | Cylindrical | Which coordinates system to use. | | | or Spherical | | | @@ -33,6 +35,13 @@ All parameters except for ``Coordinates`` and ``Angles mode`` can be specified u | | | | spherical coordinates. | +-----------------+---------------+-------------+----------------------------------------------------+ +Advanced Parameters +------------------- + +In the N-Panel (and on the right-click menu) you can find: + +**Output NumPy**: Get NumPy arrays in stead of regular lists (makes node faster) + Outputs ------- @@ -57,4 +66,3 @@ Helix: With spherical coordinates, you can easily generate complex forms: .. image:: https://cloud.githubusercontent.com/assets/284644/5840984/2e5bd24c-a1bb-11e4-97b3-99864881fa69.png - diff --git a/docs/nodes/vector/vector_polar_out.rst b/docs/nodes/vector/vector_polar_out.rst index 322c2999138e709330a63b0fad596a920c2b2bcb..861d04c8f03a779bac37f7ae50969cff322a06bb 100644 --- a/docs/nodes/vector/vector_polar_out.rst +++ b/docs/nodes/vector/vector_polar_out.rst @@ -16,12 +16,21 @@ This node has the following parameters: - **Coordinates**. Cylindrical or Spherical. Default mode is Cylindrical. - **Angles mode**. Should this node output angles measured in radians or in degrees. By default Radians. +Advanced Parameters +------------------- + +In the N-Panel (and on the right-click menu) you can find: + +**Output NumPy**: Get NumPy arrays in stead of regular lists (makes node faster) + Inputs ------ This node has one input: **Vectors** Inputs and outputs are vectorized, so if you pass series of vectors to input, you will get series of values on outputs. +The node will accept regular lists or lists of NumPy arrays if the arrays have two axis arrays with shape [n,3] + Outputs ------- @@ -38,4 +47,3 @@ Examples of usage Cube push-up: .. image:: https://cloud.githubusercontent.com/assets/284644/5841825/d0c494aa-a1c1-11e4-9c36-4c94076ba8d7.png - diff --git a/nodes/vector/vector_polar_in.py b/nodes/vector/vector_polar_in.py index ea44e1521bce076a32f6cb082442d6688650d11a..fe576d4a5965bd6af5adbf42c21fcc88aea8edcc 100644 --- a/nodes/vector/vector_polar_in.py +++ b/nodes/vector/vector_polar_in.py @@ -16,18 +16,41 @@ # # ##### END GPL LICENSE BLOCK ##### -from math import sin, cos, radians import bpy -from bpy.props import FloatProperty, EnumProperty +from bpy.props import FloatProperty, EnumProperty, BoolProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode, match_long_repeat -from sverchok.utils.math import from_cylindrical, from_spherical +from sverchok.data_structure import updateNode, match_long_repeat, numpy_match_long_repeat +from numpy import array, sin, cos, radians + +def numpy_polar_to_cartesian(ps, coordinates, angles_mode, out_numpy): + + u_rho, u_phi, u_z = [array(p) for p in ps] + + if coordinates == 'theta_': + if angles_mode == 'degrees': + ang1 = radians(u_phi) + ang2 = radians(u_z) + else: + ang1 = u_phi + ang2 = u_z + rho, phi, theta = numpy_match_long_repeat([u_rho, ang1, ang2]) + + cartesian = array([ + rho * cos(phi) * sin(theta), + rho * sin(phi) * sin(theta), + rho * cos(theta) + ]).T + else: + if angles_mode == 'degrees': + ang1 = radians(u_phi) + else: + ang1 = u_phi + rho, phi, z = numpy_match_long_repeat([u_rho, ang1, u_z]) + + cartesian = array([rho * cos(phi), rho * sin(phi), z]).T + + return cartesian if out_numpy else cartesian.tolist() -def cylindrical(rho, phi, z, mode): - return from_cylindrical(rho, phi, z, mode) - -def spherical(rho, phi, theta, mode): - return from_spherical(rho, phi, theta,mode) class VectorPolarInNode(bpy.types.Node, SverchCustomTreeNode): '''Generate vectors by spherical or cylindrical coordinates''' @@ -51,20 +74,26 @@ class VectorPolarInNode(bpy.types.Node, SverchCustomTreeNode): coord_modes = [ ("z_", "Cylinder", "Use cylindrical coordinates", 1), - ("theta_", "Sphere", "Use spherical coordinates", 2), + ("theta_", "Sphere", "Use spherical coordinates", 2), ] + + output_numpy: BoolProperty( + name='Output NumPy', + description='Output NumPy arrays', + default=False, update=updateNode) + def coordinate_changed(self, context): self.inputs[2].prop_name = self.coordinates updateNode(self, context) coordinates: EnumProperty(items=coord_modes, default='z_', update=coordinate_changed) - func_dict = {'z_': cylindrical, 'theta_': spherical} + angle_modes = [ - ("radians", "Radian", "Use angles in radians", 1), - ("degrees", "Degree", "Use angles in degrees", 2) + ("radians", "Radian", "Use angles in radians", 1), + ("degrees", "Degree", "Use angles in degrees", 2) ] angles_mode: EnumProperty(items=angle_modes, default="radians", update=updateNode) @@ -80,6 +109,16 @@ class VectorPolarInNode(bpy.types.Node, SverchCustomTreeNode): layout.prop(self, "coordinates", expand=True) layout.prop(self, "angles_mode", expand=True) + def draw_buttons_ext(self, context, layout): + layout.prop(self, "coordinates", expand=True) + layout.prop(self, "angles_mode", expand=True) + layout.prop(self, "output_numpy", toggle=False) + + def rclick_menu(self, context, layout): + layout.prop_menu_enum(self, "coordinates", text="Polar system") + layout.prop_menu_enum(self, "angles_mode", text="Angle Units") + layout.prop(self, "output_numpy", toggle=True) + def process(self): if not self.outputs['Vectors'].is_linked: return @@ -90,12 +129,9 @@ class VectorPolarInNode(bpy.types.Node, SverchCustomTreeNode): parameters = match_long_repeat([rhoss, phiss, zss]) result = [] - for rhos, phis, zs in zip(*parameters): - vs = [] - ps = match_long_repeat([rhos, phis, zs]) - for rho, phi, z in zip(*ps): - v = self.func_dict[self.coordinates](rho, phi, z, self.angles_mode) - vs.append(v) + + for ps in zip(*parameters): + vs = numpy_polar_to_cartesian(ps, self.coordinates, self.angles_mode, self.output_numpy) result.append(vs) self.outputs['Vectors'].sv_set(result) diff --git a/nodes/vector/vector_polar_out.py b/nodes/vector/vector_polar_out.py index 794ed5fe821b0d061b3ed1e6c94d0c9b0a3f2a57..267357712a065c019d24311bc9a43fb39b872003 100644 --- a/nodes/vector/vector_polar_out.py +++ b/nodes/vector/vector_polar_out.py @@ -16,18 +16,37 @@ # # ##### END GPL LICENSE BLOCK ##### -from math import sin, cos, atan, atan2, degrees, sqrt, acos + import bpy -from bpy.props import FloatProperty, EnumProperty +from bpy.props import EnumProperty, BoolProperty from sverchok.node_tree import SverchCustomTreeNode -from sverchok.data_structure import updateNode, match_long_repeat -from sverchok.utils.math import to_cylindrical, to_spherical +from sverchok.data_structure import updateNode +from numpy import array, degrees, sqrt, arctan2, linalg +from sverchok.utils.modules.vector_math_utils import angle_between + + +def numpy_cartesian_to_polar(vs, coordinates, angles_mode, out_numpy): + vecs = array(vs) + x = vecs[:, 0] + y = vecs[:, 1] + z = vecs[:, 2] + if coordinates == 'z': + rho = sqrt(x*x + y*y) + if angles_mode == "degrees": + phi = degrees(arctan2(y, x)) + else: + phi = arctan2(y, x) -def cylindrical(v, mode): - return to_cylindrical(v, mode) + else: + rho = linalg.norm(vecs, axis=1) + if angles_mode == "degrees": + phi = degrees(arctan2(y, x)) + z = degrees(angle_between(vecs, [[0, 0, 1]])) + else: + phi = arctan2(y, x) + z = angle_between(vecs, [[0, 0, 1]]) -def spherical(v, mode): - return to_spherical(v, mode) + return [rho, phi, z] if out_numpy else [rho.tolist(), phi.tolist(), z.tolist()] class VectorPolarOutNode(bpy.types.Node, SverchCustomTreeNode): '''Get cylindrical or spherical coordinates from vectors''' @@ -36,11 +55,11 @@ class VectorPolarOutNode(bpy.types.Node, SverchCustomTreeNode): bl_icon = 'OUTLINER_OB_EMPTY' sv_icon = 'SV_VECTOR_POLAR_OUT' - func_dict = {'z': cylindrical, 'theta': spherical} + coord_modes = [ ("z", "Cylinder", "Use cylindrical coordinates", 1), - ("theta", "Sphere", "Use spherical coordinates", 2), + ("theta", "Sphere", "Use spherical coordinates", 2), ] angle_modes = [ @@ -54,13 +73,22 @@ class VectorPolarOutNode(bpy.types.Node, SverchCustomTreeNode): mode_name = self.coordinates if mode_name in ['z', 'theta']: - replaceable_socket.replace_socket('SvStringsSocket', new_name = mode_name) + replaceable_socket.replace_socket('SvStringsSocket', new_name=mode_name) else: - raise Exception ("Unexpected mode - {}".format(mode_name)) + raise Exception("Unexpected mode - {}".format(mode_name)) coordinates: EnumProperty(items=coord_modes, default='z', update=coordinate_changed) angles_mode: EnumProperty(items=angle_modes, default="radians", update=updateNode) + implementation_modes = [ + ("NumPy", "NumPy", "NumPy", 0), + ("Python", "Python", "Python", 1)] + + output_numpy: BoolProperty( + name='Output NumPy', + description='Output NumPy arrays', + default=False, update=updateNode) + def sv_init(self, context): self.inputs.new("SvVerticesSocket", "Vectors") self.width = 100 @@ -72,26 +100,30 @@ class VectorPolarOutNode(bpy.types.Node, SverchCustomTreeNode): layout.prop(self, "coordinates", expand=True) layout.prop(self, "angles_mode", expand=True) + def draw_buttons_ext(self, context, layout): + layout.prop(self, "coordinates", expand=True) + layout.prop(self, "angles_mode", expand=True) + layout.prop(self, "output_numpy", toggle=False) + + def rclick_menu(self, context, layout): + layout.prop_menu_enum(self, "coordinates", text="Polar system") + layout.prop_menu_enum(self, "angles_mode", text="Angle Units") + layout.prop(self, "output_numpy", toggle=True) + def process(self): - if not (self.outputs['rho'].is_linked or self.outputs['phi'].is_linked or self.outputs[self.coordinates].is_linked): - return - vss = self.inputs['Vectors'].sv_get() + if not self.inputs[0].is_linked and (any(s.is_linked for s in self.outputs)): + return + vss = self.inputs['Vectors'].sv_get(deepcopy=False) result_rhos = [] result_phis = [] result_zs = [] for vs in vss: - rs = [] - ps = [] - zs = [] - for v in vs: - rho, phi, z = self.func_dict[self.coordinates](v, self.angles_mode) - rs.append(rho) - ps.append(phi) - zs.append(z) - result_rhos.append(rs) - result_phis.append(ps) + rhos, phis, zs = numpy_cartesian_to_polar(vs, self.coordinates, self.angles_mode, self.output_numpy) + + result_rhos.append(rhos) + result_phis.append(phis) result_zs.append(zs) if self.outputs['rho'].is_linked: