Skip to content

Commit

Permalink
Merge pull request #2993 from nortikin/extra_move
Browse files Browse the repository at this point in the history
Move what possible from Sverchok-Extra (WIP)
  • Loading branch information
portnov authored Apr 18, 2020
2 parents 4dc1341 + f1d57f3 commit 27aa44f
Show file tree
Hide file tree
Showing 229 changed files with 22,245 additions and 11 deletions.
56 changes: 55 additions & 1 deletion core/socket_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#
# ##### END GPL LICENSE BLOCK #####

from sverchok.data_structure import get_other_socket
from sverchok.data_structure import get_other_socket, get_data_nesting_level
from sverchok.utils.field.vector import SvMatrixVectorField, SvConstantVectorField
from sverchok.utils.field.scalar import SvConstantScalarField

from mathutils import Matrix, Quaternion
from numpy import ndarray
Expand Down Expand Up @@ -45,6 +47,18 @@ def is_matrix_to_quaternion(self):
def is_quaternion_to_matrix(self):
return cross_test_socket(self, 'q', 'm')

def is_matrix_to_vfield(socket):
other = get_other_socket(socket)
return other.bl_idname == 'SvMatrixSocket' and socket.bl_idname == 'SvVectorFieldSocket'

def is_vertex_to_vfield(socket):
other = get_other_socket(socket)
return other.bl_idname == 'SvVerticesSocket' and socket.bl_idname == 'SvVectorFieldSocket'

def is_string_to_sfield(socket):
other = get_other_socket(socket)
return other.bl_idname == 'SvStringsSocket' and socket.bl_idname == 'SvScalarFieldSocket'

# ---


Expand Down Expand Up @@ -119,6 +133,30 @@ def get_all(data):
get_all(data)
return [locations]

def matrices_to_vfield(data):
if isinstance(data, Matrix):
return SvMatrixVectorField(data)
elif isinstance(data, (list, tuple)):
return [matrices_to_vfield(item) for item in data]
else:
raise TypeError("Unexpected data type from Matrix socket: %s" % type(data))

def vertices_to_vfield(data):
if isinstance(data, (tuple, list)) and len(data) == 3 and isinstance(data[0], (float, int)):
return SvConstantVectorField(data)
elif isinstance(data, (list, tuple)):
return [vertices_to_vfield(item) for item in data]
else:
raise TypeError("Unexpected data type from Vertex socket: %s" % type(data))

def numbers_to_sfield(data):
if isinstance(data, (int, float)):
return SvConstantScalarField(data)
elif isinstance(data, (list, tuple)):
return [numbers_to_sfield(item) for item in data]
else:
raise TypeError("Unexpected data type from String socket: %s" % type(data))

class ImplicitConversionProhibited(Exception):
def __init__(self, socket):
super().__init__()
Expand Down Expand Up @@ -201,3 +239,19 @@ def quaternions_to_matrices(cls, socket, source_data):
@classmethod
def matrices_to_quaternions(cls, socket, source_data):
return get_quaternions_from_matrices(source_data)

class FieldImplicitConversionPolicy(DefaultImplicitConversionPolicy):
@classmethod
def convert(cls, socket, source_data):
if is_matrix_to_vfield(socket):
return matrices_to_vfield(source_data)
elif is_vertex_to_vfield(socket):
return vertices_to_vfield(source_data)
elif is_string_to_sfield(socket):
level = get_data_nesting_level(source_data)
if level > 2:
raise TypeError("Too high data nesting level for Number -> Scalar Field conversion: %s" % level)
return numbers_to_sfield(source_data)
else:
super().convert(socket, source_data)

104 changes: 102 additions & 2 deletions core/sockets.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
from bpy.props import StringProperty, BoolProperty, FloatVectorProperty, IntProperty, FloatProperty
from bpy.types import NodeTree, NodeSocket

from sverchok.core.socket_conversions import DefaultImplicitConversionPolicy, is_vector_to_matrix
from sverchok.core.socket_conversions import (
DefaultImplicitConversionPolicy,
FieldImplicitConversionPolicy,
is_vector_to_matrix
)

from sverchok.core.socket_data import (
SvGetSocketInfo, SvGetSocket, SvSetSocket,
Expand All @@ -35,6 +39,9 @@
socket_id,
replace_socket)

from sverchok.utils.field.scalar import SvConstantScalarField
from sverchok.utils.field.vector import SvMatrixVectorField, SvConstantVectorField

socket_colors = {
"SvStringsSocket": (0.6, 1.0, 0.6, 1.0),
"SvVerticesSocket": (0.9, 0.6, 0.2, 1.0),
Expand Down Expand Up @@ -591,6 +598,97 @@ def sv_get(self, default=sentinel, deepcopy=True):
def draw_color(self, context, node):
return self.dynamic_color

class SvSurfaceSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvSurfaceSocket"
bl_label = "Surface Socket"

def get_prop_data(self):
return {}

def draw_color(self, context, node):
return (0.4, 0.2, 1.0, 1.0)

def sv_get(self, default=sentinel, deepcopy=True, implicit_conversions=None):
if self.is_linked and not self.is_output:
source_data = SvGetSocket(self, deepcopy=True if self.needs_data_conversion() else deepcopy)
return self.convert_data(source_data, implicit_conversions)

if self.prop_name:
return [[getattr(self.node, self.prop_name)[:]]]
elif default is sentinel:
raise SvNoDataError(self)
else:
return default

class SvCurveSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvCurveSocket"
bl_label = "Curve Socket"

def get_prop_data(self):
return {}

def draw_color(self, context, node):
return (0.5, 0.6, 1.0, 1.0)

def sv_get(self, default=sentinel, deepcopy=True, implicit_conversions=None):
if self.is_linked and not self.is_output:
source_data = SvGetSocket(self, deepcopy=True if self.needs_data_conversion() else deepcopy)
return self.convert_data(source_data, implicit_conversions)

if self.prop_name:
return [[getattr(self.node, self.prop_name)[:]]]
elif default is sentinel:
raise SvNoDataError(self)
else:
return default

class SvScalarFieldSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvScalarFieldSocket"
bl_label = "Scalar Field Socket"

def get_prop_data(self):
return {}

def draw_color(self, context, node):
return (0.9, 0.4, 0.1, 1.0)

def sv_get(self, default=sentinel, deepcopy=True, implicit_conversions=None):
if implicit_conversions is None:
implicit_conversions = FieldImplicitConversionPolicy
if self.is_linked and not self.is_output:
source_data = SvGetSocket(self, deepcopy=True if self.needs_data_conversion() else deepcopy)
return self.convert_data(source_data, implicit_conversions)

if self.prop_name:
return [[getattr(self.node, self.prop_name)[:]]]
elif default is sentinel:
raise SvNoDataError(self)
else:
return default

class SvVectorFieldSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvVectorFieldSocket"
bl_label = "Vector Field Socket"

def get_prop_data(self):
return {}

def draw_color(self, context, node):
return (0.1, 0.1, 0.9, 1.0)

def sv_get(self, default=sentinel, deepcopy=True, implicit_conversions=None):
if implicit_conversions is None:
implicit_conversions = FieldImplicitConversionPolicy
if self.is_linked and not self.is_output:
source_data = SvGetSocket(self, deepcopy=True if self.needs_data_conversion() else deepcopy)
return self.convert_data(source_data, implicit_conversions)

if self.prop_name:
return [[getattr(self.node, self.prop_name)[:]]]
elif default is sentinel:
raise SvNoDataError(self)
else:
return default

"""
type_map_to/from are used to get the bl_idname from a single letter
Expand Down Expand Up @@ -621,7 +719,9 @@ def draw_color(self, context, node):
classes = [
SvVerticesSocket, SvMatrixSocket, SvStringsSocket,
SvColorSocket, SvQuaternionSocket, SvDummySocket, SvSeparatorSocket,
SvTextSocket, SvObjectSocket, SvDictionarySocket, SvChameleonSocket
SvTextSocket, SvObjectSocket, SvDictionarySocket, SvChameleonSocket,
SvSurfaceSocket, SvCurveSocket, SvScalarFieldSocket, SvVectorFieldSocket
]

register, unregister = bpy.utils.register_classes_factory(classes)

95 changes: 95 additions & 0 deletions docs/curves.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@

Curve
-----

Sverchok uses the term **Curve** mostly in the same way as it is used in mathematics.

From the user perspective, a Curve object is just a (more or less smooth) curve
laying in 3D space, which goes from one point (start) to another point (end).
The start and the end point of the curve may coincide, in this case we say the
curve is **closed**, or **cyclic**.

Let's state some properties of the Curve object, which will define our
understanding of this term in context of Sverchok:

* A curve is a finite, one-dimensional object, existing in 3D space.
* Every curve must have exactly two endpoints. No more, no less.
* If the endpoints coincide, the curve is considered to be closed.
* There may be no gaps on the interior of a curve, as that would result in more
than two endpoints.
* There may be no branching points on the curve, except where an endpoint is
coincident with some interior point of the curve.

Mathematically, a Curve is a set of points in 3D space, which can be defined as
a codomain of some function from R to R^3; i.e. the function, which maps some
real number to a vector in 3D space. We will be considering only "good enough"
functions; more exactly, such function must be continuous, and have at least 3
derivatives at (mostly) each point.

It is important to understand, that each curve can be defined by more than one
function (which is called parameterization of the curve). We usually use the
one which is most fitting our goals in specific task.

Usually we use the letter **t** for curve parameter; in some case the letter **u** is used.

For example, let's consider a straight line segment, which is beginning at `(0,
0, 0)` and ending at `(1, 1, 1)`. The following parameterizations all define
the same line:

A)

x(t) = t

y(t) = t

z(t) = t

B)
x(t) = t^2

y(t) = t^2

z(t) = t^2

C)

x(t) = t^3

y(t) = t^3

z(t) = t^3

As you understand, we can write down as many equations for it as we want.

Different parametrizations of the same curve can have different values of **t**
parameter corresponding to the beginning and the end of the curve. For example,

D)
x(t) = t - 1

y(t) = t - 1

z(t) = t - 1

defines the parametrization, for which `t = 1` corresponds to the beginning of
the segment, and `t = 2` corresponds to the end of the segment. The range of
the curve parameter which corresponds to the curve from it's beginning to the
end is called **curve domain**.

Another important thing to understand is that the value of curve parameter at
some point has nothing to do with the length of the curve. With our straight
line example, if we consider A) parametrization at the point of `t = 0.5`, it
will be `(0.5, 0.5, 0.5)`, i.e. the middle of the segment. But, if we take the
same segment with B) parametrization, `t = 0.5` will give us `(0.25, 0.25,
0.25)`, which is not the middle of the segment at all.

Among all possible parametrizations of a curve, one is distinguished. It is
called **natural parametrization**. The natural parametrization of the curve
has the property: certain change in **t** parameter corresponds to exactly the
same change in curve length. Each curve has exactly one natural
parametrization.

Since Blender has mostly mesh-based approach to modelling, as well as Sverchok,
to "visualize" the Curve object, you have to convert it to mesh. It is usually
done by use of "Evaluate Curve" node, or "Curve Length Parameter" node.

32 changes: 32 additions & 0 deletions docs/fields.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

Scalar Fields
-------------

A scalar field is a mathematical object, which is defined as a function from R^3 to R, i.e. a mapping which maps each point in a 3D space to some number. Such objects are quite common in mathematics and in physics too; for example, you can take a field of temperatures (which maps each point to the temperature in that point).

Technically, scalar field is defined as Python class, which can calculate some number for a provided point in space. Note that the definition of the field function can be quite complex, but it does not mean that that complex definition will be executed for all points in 3D space — only for points for which it is actually required to know the value.

Sverchok can generate such fields by several ways, including user-provided formulas; it can execute some mathematical operations on them (such as addition or multiplication).

Vector Fields
-------------

A vector field is a mathematical object, which is defined as a function from R^3 to R^3, i.e. a mapping which maps each point in 3D space into a 3D vector. Such objects are very common in mathematics and in physics; for example, consider the field of some force, for example the gravitation field, which defines the gravitation force vector for each point in space.

Note that when we are talking about vector fields, there are two possible ways to interpret their values:

1. to think that the vector, which is defined by vector field in point P, starts in point P and ends in some point P';
2. to think that the vector which is defined by vector field in point P, starts in the origin and ends in some point Q.

In physics, the first approach is the most common, and it is mostly used by Sverchok.

One can note, that both approaches are easily convertible: if you have a field, which maps point P to a vector from 0 to Q, then you can say that you have a field which maps point P to a vector from P to (P+Q). Or the other way around, if you have a field which maps point P to a vector from P to P', then you can say that you have a field which maps point P to a vector from 0 to (P' - P).

"Apply vector field" node follows the first approach, i.e. for each provided point P it returns the point to which P would be mapped if we understand that the vector VectorField(P) starts at P. Mathematically, it returns `P + VectorField(P)`. In most cases, you will want to use this node instead of "evaluate vector field".

"Evaluate vector field" node, on the other hand, follows the second approach, i.e. for each point P it returns VectorField(P).

Technically, vector field is a Python class that can be asked to return a vector for any 3D point. Note that the definition of the field function can be quite complex, but it does not mean that that complex definition will be executed for all points in 3D space — only for points for which it is actually required to know the value.

Sverchok can generate such fields by several ways, including user-provided formulas; it can execute some mathematical operations on them (such as addition or multiplication). Vector field can be applied to some set of vertices to receive another one — i.e., deform some mesh by field. There are also several ways to convert vector fields to scalar fields (for example, you can take a norm of the vector field, or use divergence differential operator).

14 changes: 8 additions & 6 deletions docs/geometry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ further study::

List, Index, Vector, Vertex, Edge, Polygon, Normal, Transformation, and Matrix.

Also, Sverchok uses the following terms to generate and modify geometrical entities:

* Curve
* Surface
* Scalar Field
* Vector Field

Although the terms by theirselve are of common use and most probably you know them, there are some things we have to discuss about them in Sverchok context. They will be discussed in corresponding paragraphs below.

List
----
Expand Down Expand Up @@ -182,9 +190,3 @@ Ready?
I think this broadly covers the things you should be
comfortable with before Sverchok will make sense.


Sverchok
--------

This section will introduce you to a selection of nodes that can be combined
to create renderable geometry. Starting with the simple Plane generator
3 changes: 3 additions & 0 deletions docs/induction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Introduction to Sverchok

You have installed the addon, if not then read the installation notes. If you've ever used Nodes for anything in Blender, Cycles / Compositor Nodes feel free to continue straight to Unit 01 if you see the RNA icon in the list of NodeView types.

This section will introduce you to a selection of nodes that can be combined
to create renderable geometry. Starting with the simple Plane generator

Unit 00 - Introduction to NodeView and 3DView
---------------------------------------------

Expand Down
3 changes: 3 additions & 0 deletions docs/main.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Contents:

installation
geometry
curves
surfaces
fields
induction
panels
nodes
Expand Down
3 changes: 3 additions & 0 deletions docs/nodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Nodes

Generators <nodes/generator/generator_index>
Generators Extended<nodes/generators_extended/generators_extended_index>
Curves<nodes/curve/curve_index>
Surfaces<nopdes/surface/surface_index>
Fields<nodes/field/field_index>
Transforms <nodes/transforms/transforms_index>
Analyzers <nodes/analyzer/analyzer_index>
Modifier Change <nodes/modifier_change/modifier_change_index>
Expand Down
Loading

0 comments on commit 27aa44f

Please sign in to comment.