Не подтверждена Коммит e9c3df54 создал по автору Ilya V. Portnov's avatar Ilya V. Portnov Зафиксировано автором GitHub
Просмотр файлов

Merge pull request #2653 from nortikin/dual_mesh

Dual mesh node
владельцы 31db2e51 90b3576e
Dual Mesh
=========
Functionality
-------------
This node generates dual mesh for the given mesh. Dual mesh is defined as a
mesh which has vertices at center of each face of source mesh; edges of the
dual mesh connect the vertices, which correspond to faces of original mesh with
common edge.
This node may be useful to convert the mesh consisting of Tris to mesh
consisting to NGons, or backwards.
Note that the volume of dual mesh is always a bit smaller than that of original mesh.
Inputs
------
This node has the following inputs:
- **Vertices**. Vertices of original mesh. This input is mandatory.
- **Edges**. Edges of original mesh.
- **Faces**. Faces of original mesh. This input is mandatory.
Outputs
-------
This node has the following outputs:
- **Vertices**. Vertices of the dual mesh.
- **Faces**. Faces of the dual mesh.
Examples of Usage
-----------------
Dual mesh for cube is an octahedron:
.. image:: https://user-images.githubusercontent.com/284644/68086032-278bb800-fe69-11e9-80d5-5b46bde8d9b0.png
Dual mesh for Voronoi diagram is Delaunay triangulation:
.. image:: https://user-images.githubusercontent.com/284644/68086114-fcee2f00-fe69-11e9-95f5-d57f03dbbf0f.png
...@@ -23,3 +23,5 @@ Modifier Make ...@@ -23,3 +23,5 @@ Modifier Make
contour2D contour2D
fractal_curve fractal_curve
convex_hull_mk2 convex_hull_mk2
dual_mesh
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
Voronoi2DNode Voronoi2DNode
SvOffsetLineNode SvOffsetLineNode
SvContourNode SvContourNode
SvDualMeshNode
--- ---
SvBevelCurveNode SvBevelCurveNode
SvAdaptiveEdgeNode SvAdaptiveEdgeNode
......
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import operator
import bpy
from mathutils import Matrix, Vector
from bpy.props import IntProperty, FloatProperty, EnumProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import (Vector_generate, updateNode,
match_long_repeat)
from sverchok.utils.sv_bmesh_utils import pydata_from_bmesh, bmesh_from_pydata, dual_mesh
class SvDualMeshNode(bpy.types.Node, SverchCustomTreeNode):
"""
Trigers: Dual Mesh
Tooltip: Create dual mesh for the given mesh
"""
bl_idname = 'SvDualMeshNode'
bl_label = "Dual Mesh"
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_DUAL_MESH'
def sv_init(self, context):
self.inputs.new('SvVerticesSocket', 'Vertices')
self.inputs.new('SvStringsSocket', 'Edges')
self.inputs.new('SvStringsSocket', 'Faces')
self.outputs.new('SvVerticesSocket', 'Vertices')
self.outputs.new('SvStringsSocket', 'Faces')
def process(self):
if not any((s.is_linked for s in self.outputs)):
return
verts_s = self.inputs['Vertices'].sv_get()
edges_s = self.inputs['Edges'].sv_get(default=[[]])
faces_s = self.inputs['Faces'].sv_get()
verts_out = []
faces_out = []
objects = match_long_repeat([verts_s, edges_s, faces_s])
for verts, edges, faces in zip(*objects):
bm = bmesh_from_pydata(verts, edges, faces)
new_verts, new_faces = dual_mesh(bm)
bm.free()
new_verts = [tuple(v) for v in new_verts]
verts_out.append(new_verts)
faces_out.append(new_faces)
self.outputs['Vertices'].sv_set(verts_out)
self.outputs['Faces'].sv_set(faces_out)
def register():
bpy.utils.register_class(SvDualMeshNode)
def unregister():
bpy.utils.unregister_class(SvDualMeshNode)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg8"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="sv_dual_mesh.svg"
inkscape:export-filename="/home/portnov/src/sverchok_280/ui/icons/sv_dual_mesh.svg.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="6.7533541"
inkscape:cx="18.270351"
inkscape:cy="22.983318"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1916"
inkscape:window-height="1196"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid4512" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-280.06665)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.79374999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 8.6049118,290.04704 v 6.1402"
id="path863"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path869"
d="M 1.4157376,293.03879 H 15.71573"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 10.577676,280.97023 1.7740673,296.0964"
id="path871"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path875"
d="M 6.4362568,280.97023 15.239866,296.0964"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path879"
d="M 9.6787516,289.02136 16.18718,285.41481"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.79374999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.79374999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 7.2545818,289.02136 0.74615317,285.41481"
id="path881"
inkscape:connector-curvature="0" />
<rect
y="289.02188"
x="7.4522281"
height="2.2270114"
width="2.2270114"
id="rect877"
style="opacity:1;vector-effect:none;fill:#babdb6;fill-opacity:1;stroke:#000000;stroke-width:0.51999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:markers fill stroke" />
</g>
</svg>
...@@ -161,3 +161,61 @@ def remove_doubles(vertices, edges, faces, d): ...@@ -161,3 +161,61 @@ def remove_doubles(vertices, edges, faces, d):
v, e, p =pydata_from_bmesh(bm) v, e, p =pydata_from_bmesh(bm)
bm.free() bm.free()
return v, e, p return v, e, p
def dual_mesh(bm, recalc_normals=True):
# Make vertices of dual mesh by finding
# centers of original mesh faces.
new_verts = dict()
for face in bm.faces:
new_verts[face.index] = face.calc_center_median()
#new_edges = []
new_faces = []
# For each vertex of original mesh,
# find all connected faces and connect
# corresponding vertices of the dual mesh
# with a face.
# The problem is, that the order of edges in
# vert.link_edges (or faces in vert.link_faces)
# is undefined, so we have to sort them somehow.
for vert in bm.verts:
if not vert.link_faces:
continue
face0 = vert.link_faces[0]
new_face = [face0.index]
other_faces = set(vert.link_faces[:])
n = len(vert.link_faces)
while other_faces:
n = n-1
if n <= 0:
break
for edge in vert.link_edges:
if face0 in edge.link_faces:
fcs = [face for face in edge.link_faces if face != face0]
if not fcs:
continue
other_face = fcs[0]
if other_face in other_faces:
face0 = other_face
other_faces.remove(face0)
if face0.index not in new_face:
new_face.append(face0.index)
if len(new_face) > 2:
new_faces.append(new_face)
vertices = [new_verts[idx] for idx in sorted(new_verts.keys())]
# We cannot guarantee that our sorting above gave us faces
# of original mesh in counterclockwise order each time.
# So if we want normals of dual mesh to be consistent,
# we have to call bmesh.ops.recalc_face_normals.
if not recalc_normals:
return vertices, new_faces
else:
bm2 = bmesh_from_pydata(vertices, [], new_faces, normal_update=True)
bmesh.ops.recalc_face_normals(bm2, faces=bm2.faces)
new_vertices, new_edges, new_faces = pydata_from_bmesh(bm2)
bm2.free()
return new_vertices, new_faces
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать