From ee20f64e7705ac2ad7131f92a6cdc842254b181f Mon Sep 17 00:00:00 2001 From: Victor Doval <10011941+vicdoval@users.noreply.github.com> Date: Tue, 11 Aug 2020 12:24:08 +0200 Subject: [PATCH] Slice solid node --- docs/nodes/solid/slice_solid.rst | 41 ++++++ docs/nodes/solid/solid_index.rst | 1 + index.md | 1 + nodes/solid/slice_solid.py | 87 ++++++++++++ nodes/solid/solid_faces.py | 57 +------- ui/icons/sv_slice_solid.png | Bin 0 -> 2870 bytes ui/icons/svg/sv_slice_solid.svg | 225 +++++++++++++++++++++++++++++++ utils/surface/__init__.py | 4 +- utils/surface/freecad.py | 65 +++++++++ 9 files changed, 423 insertions(+), 58 deletions(-) create mode 100644 docs/nodes/solid/slice_solid.rst create mode 100644 nodes/solid/slice_solid.py create mode 100644 ui/icons/sv_slice_solid.png create mode 100644 ui/icons/svg/sv_slice_solid.svg create mode 100644 utils/surface/freecad.py diff --git a/docs/nodes/solid/slice_solid.rst b/docs/nodes/solid/slice_solid.rst new file mode 100644 index 000000000..8912929d5 --- /dev/null +++ b/docs/nodes/solid/slice_solid.rst @@ -0,0 +1,41 @@ +Solid Distance +============== + +Dependencies +------------ + +This node requires FreeCAD_ library to work. + +.. _FreeCAD: ../../solids.rst + +Functionality +------------- + +The node returns a slice of the solid object. + +Options +------- + +**Flat Output**: If the input has two solids the output will have two groups of curves. If Flat Output is enabled the two groups will be merged in a single group [[curve, curve,..], [curve, curve,...]] to [curve, curve, curve...] + +Inputs +------ + +All inputs are vectorized and the data will be matched to the longest list + +- **Solid**: Object to slice +- **Matrix**: Cutting plane + +Outputs +------- + +- **Edges**: Edges (Curves) that define the slice. +- **Faces**: The slice as a Solid Face Surface. + + +Examples +-------- + +.. image:: https://raw.githubusercontent.com/vicdoval/sverchok/docs_images/images_for_docs/solid/slice_solid/slice_solid_blender_sverchok_example_00.png + +.. image:: https://raw.githubusercontent.com/vicdoval/sverchok/docs_images/images_for_docs/solid/slice_solid/slice_solid_blender_sverchok_example_01.png diff --git a/docs/nodes/solid/solid_index.rst b/docs/nodes/solid/solid_index.rst index da162b84c..2b1b6c779 100644 --- a/docs/nodes/solid/solid_index.rst +++ b/docs/nodes/solid/solid_index.rst @@ -18,6 +18,7 @@ Solid offset_solid points_inside_solid solid_distance + slice_solid mesh_to_solid solid_to_mesh solid_faces diff --git a/index.md b/index.md index 8567e14df..07a62e011 100644 --- a/index.md +++ b/index.md @@ -206,6 +206,7 @@ SvOffsetSolidNode SvIsInsideSolidNode SvSolidDistanceNode + SvSliceSolidNode SvMeshToSolidNode SvSolidToMeshNode SvSolidVerticesNode diff --git a/nodes/solid/slice_solid.py b/nodes/solid/slice_solid.py new file mode 100644 index 000000000..4ee669945 --- /dev/null +++ b/nodes/solid/slice_solid.py @@ -0,0 +1,87 @@ + +from sverchok.dependencies import FreeCAD +from sverchok.utils.dummy_nodes import add_dummy + +if FreeCAD is None: + add_dummy('SvTransformSolidNode', 'Transform Solid', 'FreeCAD') +else: + import bpy + from mathutils import Vector + from bpy.props import BoolProperty + + from sverchok.node_tree import SverchCustomTreeNode + from sverchok.data_structure import updateNode, match_long_repeat as mlr + from FreeCAD import Base + import Part + from sverchok.utils.curve import SvSolidEdgeCurve + from sverchok.utils.surface import SvSolidFaceSurface + + class SvSliceSolidNode(bpy.types.Node, SverchCustomTreeNode): + """ + Triggers: Apply Matrix to Solid + Tooltip: Transform Solid with Matrix + """ + bl_idname = 'SvSliceSolidNode' + bl_label = 'Slice Solid' + bl_icon = 'MESH_CUBE' + sv_icon = 'SV_SLICE_SOLID' + solid_catergory = "Operators" + + flat_output: BoolProperty( + name="Flat Output", + default=False, + update=updateNode) + + def sv_init(self, context): + self.inputs.new('SvSolidSocket', "Solid") + self.inputs.new('SvMatrixSocket', "Matrix") + + self.outputs.new('SvCurveSocket', "Edges") + self.outputs.new('SvSurfaceSocket', "Faces") + + def draw_buttons(self, context, layout): + layout.prop(self, 'flat_output') + + def process(self): + if not any(socket.is_linked for socket in self.outputs): + return + + solids_in = self.inputs[0].sv_get(deepcopy=False) + matrixes = self.inputs[1].sv_get(deepcopy=False) + slices = [] + slices_face = [] + faces_add = slices_face.extend if self.flat_output else slices_face.append + slices_add = slices.extend if self.flat_output else slices.append + + for solid, matrix in zip(*mlr([solids_in, matrixes])): + + location = matrix.decompose()[0] + norm = (matrix @ Vector((0, 0, 1))) - location + dist = norm.dot(location) + + wires = solid.slice(Base.Vector(norm), dist) + edges_curves = [] + faces = [] + for wire in wires: + for edge in wire.Edges: + curve = SvSolidEdgeCurve(edge) + edges_curves.append(curve) + face = Part.Face(wire) + faces.append(SvSolidFaceSurface(face)) + if faces: + faces_add(faces) + if edges_curves: + slices_add(edges_curves) + + self.outputs['Edges'].sv_set(slices) + self.outputs['Faces'].sv_set(slices_face) + + + +def register(): + if FreeCAD is not None: + bpy.utils.register_class(SvSliceSolidNode) + +def unregister(): + if FreeCAD is not None: + bpy.utils.unregister_class(SvSliceSolidNode) diff --git a/nodes/solid/solid_faces.py b/nodes/solid/solid_faces.py index 6f13e9864..a60c3103b 100644 --- a/nodes/solid/solid_faces.py +++ b/nodes/solid/solid_faces.py @@ -12,62 +12,7 @@ else: from sverchok.data_structure import updateNode from sverchok.utils.surface import SvSurface from sverchok.utils.curve import SvSolidEdgeCurve - - class SvSolidFaceSurface(SvSurface): - __description__ = "Solid Face" - def __init__(self, solid_face): - self.face = solid_face - self.surface = solid_face.Surface - self.u_bounds = solid_face.ParameterRange[:2] - self.v_bounds = solid_face.ParameterRange[2:] - def get_u_min(self): - return self.u_bounds[0] - - def get_u_max(self): - return self.u_bounds[1] - - def get_v_min(self): - return self.v_bounds[0] - - def get_v_max(self): - return self.v_bounds[1] - - @property - def u_size(self): - return self.u_bounds[1] - self.u_bounds[0] - - @property - def v_size(self): - return self.v_bounds[1] - self.v_bounds[0] - - def evaluate(self, u, v): - return np.array(self.surface.value(u, v)) - - def evaluate_array(self, us, vs): - v_out = [] - for u,v in zip(us, vs): - v_out.append(self.surface.value(u, v)) - return np.array(v_out) - - def gauss_curvature_array(self, us, vs): - v_out = [] - for u,v in zip(us, vs): - v_out.append(self.surface.curvature(u, v, "Gauss")) - return np.array(v_out) - def mean_curvature_array(self, us, vs): - v_out = [] - for u,v in zip(us, vs): - v_out.append(self.surface.curvature(u, v, "Mean")) - return np.array(v_out) - - def normal(self, u, v): - return np.array(self.surface.normal(u, v)) - - def normal_array(self, us, vs): - v_out = [] - for u,v in zip(us, vs): - v_out.append(self.surface.normal(u, v)) - return np.array(v_out) + from sverchok.utils.surface import SvSolidFaceSurface class SvSolidFacesNode(bpy.types.Node, SverchCustomTreeNode): diff --git a/ui/icons/sv_slice_solid.png b/ui/icons/sv_slice_solid.png new file mode 100644 index 0000000000000000000000000000000000000000..e931b716ff5b68fd64b5cda67f6f57b25ec3e72e GIT binary patch literal 2870 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 Uhb4HBod5s;07*qoM6N<$f(8~@9{>OV literal 0 HcmV?d00001 diff --git a/ui/icons/svg/sv_slice_solid.svg b/ui/icons/svg/sv_slice_solid.svg new file mode 100644 index 000000000..8615b50b7 --- /dev/null +++ b/ui/icons/svg/sv_slice_solid.svg @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/utils/surface/__init__.py b/utils/surface/__init__.py index 9d38e9090..7f0239b00 100644 --- a/utils/surface/__init__.py +++ b/utils/surface/__init__.py @@ -1,7 +1,7 @@ # This file is part of project Sverchok. It's copyrighted by the contributors # recorded in the version control history of the file, available from # its original location https://github.com/nortikin/sverchok/commit/master -# +# # SPDX-License-Identifier: GPL3 # License-Filename: LICENSE @@ -9,4 +9,4 @@ from sverchok.utils.surface.core import * from sverchok.utils.surface.data import * from sverchok.utils.surface.sphere import * from sverchok.utils.surface.primitives import * - +from sverchok.utils.surface.freecad import * diff --git a/utils/surface/freecad.py b/utils/surface/freecad.py new file mode 100644 index 000000000..af818ae5f --- /dev/null +++ b/utils/surface/freecad.py @@ -0,0 +1,65 @@ +# This file is part of project Sverchok. It's copyrighted by the contributors +# recorded in the version control history of the file, available from +# its original location https://github.com/nortikin/sverchok/commit/master +# +# SPDX-License-Identifier: GPL3 +# License-Filename: LICENSE + +import numpy as np +from sverchok.utils.surface.core import SvSurface + +class SvSolidFaceSurface(SvSurface): + __description__ = "Solid Face" + def __init__(self, solid_face): + self.face = solid_face + self.surface = solid_face.Surface + self.u_bounds = solid_face.ParameterRange[:2] + self.v_bounds = solid_face.ParameterRange[2:] + def get_u_min(self): + return self.u_bounds[0] + + def get_u_max(self): + return self.u_bounds[1] + + def get_v_min(self): + return self.v_bounds[0] + + def get_v_max(self): + return self.v_bounds[1] + + @property + def u_size(self): + return self.u_bounds[1] - self.u_bounds[0] + + @property + def v_size(self): + return self.v_bounds[1] - self.v_bounds[0] + + def evaluate(self, u, v): + return np.array(self.surface.value(u, v)) + + def evaluate_array(self, us, vs): + v_out = [] + for u, v in zip(us, vs): + v_out.append(self.surface.value(u, v)) + return np.array(v_out) + + def gauss_curvature_array(self, us, vs): + v_out = [] + for u, v in zip(us, vs): + v_out.append(self.surface.curvature(u, v, "Gauss")) + return np.array(v_out) + def mean_curvature_array(self, us, vs): + v_out = [] + for u,v in zip(us, vs): + v_out.append(self.surface.curvature(u, v, "Mean")) + return np.array(v_out) + + def normal(self, u, v): + return np.array(self.surface.normal(u, v)) + + def normal_array(self, us, vs): + v_out = [] + for u,v in zip(us, vs): + v_out.append(self.surface.normal(u, v)) + return np.array(v_out) -- GitLab