[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [1885] contrib/py/scripts/addons/ wetted_mesh.py: first commit wetted_mesh.py in contrib ( renamed from add_interface_meshes in external)

Kai Schwebke kai at schwebke.com
Sun May 1 11:10:11 CEST 2011


Revision: 1885
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=1885
Author:   freejack
Date:     2011-05-01 09:10:11 +0000 (Sun, 01 May 2011)
Log Message:
-----------
first commit wetted_mesh.py in contrib (renamed from add_interface_meshes in external)

Added Paths:
-----------
    contrib/py/scripts/addons/wetted_mesh.py

Added: contrib/py/scripts/addons/wetted_mesh.py
===================================================================
--- contrib/py/scripts/addons/wetted_mesh.py	                        (rev 0)
+++ contrib/py/scripts/addons/wetted_mesh.py	2011-05-01 09:10:11 UTC (rev 1885)
@@ -0,0 +1,377 @@
+# ##### 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 #####
+
+bl_info = {
+    "name": "Add Wetted Mesh",
+    "author": "freejack",
+    "version": (0, 2),
+    "blender": (2, 5, 7),
+    "api": 35853,
+    "location": "View3D > Tool Shelf > Wetted Mesh Panel",
+    "description": "Adds separated fluid, dry and wetted mesh for selected pair.",
+    "warning": "",
+    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
+        "Scripts/Mesh/Wetted_Mesh",
+    "tracker_url": "http://projects.blender.org/tracker/index.php?"\
+        "func=detail&aid=27156",
+    "category": "Mesh"}
+
+import bpy
+import collections
+import math
+
+### Tool Panel ###
+class VIEW3D_PT_tools_WettedMesh(bpy.types.Panel):
+    '''Wetted Mesh Tool Panel'''
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_label = 'Wetted Mesh'
+    bl_context = 'objectmode'
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=True)
+        slcnt = len(context.selected_objects)
+
+        if slcnt != 2:
+           col.label(text = 'Select two mesh objects')
+           col.label(text = 'to generate separated')
+           col.label(text = 'fluid, dry and wetted')
+           col.label(text = 'meshes.')
+        else:
+           (solid, fluid) = getSelectedPair(context)
+           col.label(text = 'solid = '+solid.name)
+           col.label(text = 'fluid = '+fluid.name)
+           col.operator('mesh.primitive_wetted_mesh_add', text='Generate Meshes')
+
+### Operator ###
+class AddWettedMesh(bpy.types.Operator):
+    '''Add wetted mesh for selected mesh pair'''
+    bl_idname = "mesh.primitive_wetted_mesh_add"
+    bl_label = "Add Wetted Mesh"
+    bl_options = {'REGISTER', 'UNDO'}
+    statusMessage = ''
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=True)
+        col.label(text = self.statusMessage)
+
+    def execute(self, context):
+        # make sure a pair of objects is selected
+        if len(context.selected_objects) != 2:
+            # should not happen if called from tool panel
+            self.report({'WARNING'}, "no mesh pair selected, operation cancelled")
+            return {'CANCELLED'}
+
+        print("add_wetted_mesh begin")
+        
+        # super-selected object is solid, other object is fluid
+        (solid, fluid) = getSelectedPair(context)
+        print("   solid = "+solid.name)
+        print("   fluid = "+fluid.name)
+            
+        # make a copy of fluid object, convert to mesh if required
+        print("   copy fluid")
+        bpy.ops.object.select_all(action='DESELECT')
+        fluid.select = True
+        context.scene.objects.active = fluid
+        bpy.ops.object.duplicate()
+        bpy.ops.object.convert(target='MESH', keep_original=False)
+        bpy.ops.object.location_apply()
+        bpy.ops.object.rotation_apply()
+        bpy.ops.object.scale_apply()
+        fluidCopy = context.object
+        
+        # substract solid from fluidCopy
+        print("   bool: fluidCopy DIFFERENCE solid")
+        bpy.ops.object.modifier_add(type='BOOLEAN')
+        bop = fluidCopy.modifiers.items()[0]
+        bop[1].operation = 'DIFFERENCE'
+        bop[1].object = solid
+        bpy.ops.object.modifier_apply(apply_as='DATA', modifier=bop[0])
+        fluidMinusSolid = fluidCopy
+        fluidMinusSolid.name = "fluidMinusSolid"
+        
+        # make a second copy of fluid object
+        print("   copy fluid")
+        bpy.ops.object.select_all(action='DESELECT')
+        fluid.select = True
+        context.scene.objects.active = fluid
+        bpy.ops.object.duplicate()
+        bpy.ops.object.convert(target='MESH', keep_original=False)
+        bpy.ops.object.location_apply()
+        bpy.ops.object.rotation_apply()
+        bpy.ops.object.scale_apply()
+        fluidCopy = context.object
+        
+        # make union from fluidCopy and solid
+        print("   bool: fluidCopy UNION solid")
+        bpy.ops.object.modifier_add(type='BOOLEAN')
+        bop = fluidCopy.modifiers.items()[0]
+        bop[1].operation = 'UNION'
+        bop[1].object = solid
+        bpy.ops.object.modifier_apply(apply_as='DATA', modifier=bop[0])
+        fluidUnionSolid = fluidCopy
+        fluidUnionSolid.name = "fluidUnionSolid"
+        
+        # index meshes
+        print("   KDTree index fluidMinusSolid")
+        fluidMinusSolidKDT = KDTree(3, fluidMinusSolid.data.vertices)
+        print("   KDTree index fluidUnionSolid")
+        fluidUnionSolidKDT = KDTree(3, fluidUnionSolid.data.vertices)
+        kdtrees = (fluidMinusSolidKDT, fluidUnionSolidKDT)
+        
+        # build mesh face sets
+        faceDict = { }
+        vertDict = { }
+        
+        print("   processing fluidMinusSolid faces")
+        cacheDict = { }
+        setFMSfaces = set()
+        numFaces = len(fluidUnionSolid.data.faces)
+        i = 0
+        for f in fluidMinusSolid.data.faces:
+            if i % 500 == 0:
+               print("      ", i, " / ", numFaces)
+            i += 1
+            fuid = unifiedFaceId(kdtrees, f, fluidMinusSolid.data.vertices, \
+                                 faceDict, vertDict, cacheDict)
+            setFMSfaces.add(fuid)
+        
+        print("   processing fluidUnionSolid faces")
+        cacheDict = { }
+        setFUSfaces = set()
+        numFaces = len(fluidUnionSolid.data.faces)
+        i = 0
+        for f in fluidUnionSolid.data.faces:
+            if i % 500 == 0:
+               print("      ", i, " / ", numFaces)
+            i += 1
+            fuid = unifiedFaceId(kdtrees, f, fluidUnionSolid.data.vertices, \
+                                 faceDict, vertDict, cacheDict)
+            setFUSfaces.add(fuid)
+        
+        # remove boolean helpers
+        print("   delete helper objects")
+        bpy.ops.object.select_all(action='DESELECT')
+        fluidUnionSolid.select = True
+        fluidMinusSolid.select = True
+        bpy.ops.object.delete()
+
+        # wetted = FMS - FUS
+        print("   set operation FMS diff FUS")
+        setWetFaces = setFMSfaces.difference(setFUSfaces)
+        print("   build wetted mesh")
+        verts, faces = buildMesh(setWetFaces, faceDict, vertDict)
+        print("   create wetted mesh")
+        wetted = createMesh("Wetted", verts, faces)
+
+        # fluid = FMS x FUS
+        print("   set operation FMS intersect FUS")
+        setFluidFaces = setFMSfaces.intersection(setFUSfaces)
+        print("   build fluid mesh")
+        verts, faces = buildMesh(setFluidFaces, faceDict, vertDict)
+        print("   create fluid mesh")
+        fluid = createMesh("Fluid", verts, faces)
+        
+        # solid = FUS - FMS
+        print("   set operation FUS diff FMS")
+        setSolidFaces = setFUSfaces.difference(setFMSfaces)
+        print("   build solid mesh")
+        verts, faces = buildMesh(setSolidFaces, faceDict, vertDict)
+        print("   create solid mesh")
+        solid = createMesh("Solid", verts, faces)
+        
+        # parent wetted mesh
+        print("   parent mesh")
+        bpy.ops.object.add(type='EMPTY')
+        wettedMesh = context.object
+        solid.select = True
+        fluid.select = True
+        wetted.select = True
+        wettedMesh.select = True
+        bpy.ops.object.parent_set(type='OBJECT')
+        wettedMesh.name = 'WettedMesh'
+        
+        print("add_wetted_mesh done")
+        self.statusMessage = 'created '+wettedMesh.name
+
+        return {'FINISHED'}
+
+
+### Registration ###
+def register():
+    bpy.utils.register_class(VIEW3D_PT_tools_WettedMesh)
+    bpy.utils.register_class(AddWettedMesh)
+
+
+def unregister():
+    bpy.utils.unregister_class(VIEW3D_PT_tools_WettedMesh)
+    bpy.utils.unregister_class(AddWettedMesh)
+
+if __name__ == "__main__":
+    register()
+
+
+#
+# KD tree (used to create a geometric index of mesh vertices)
+#
+
+def distance(a, b):
+    return (a-b).length
+
+Node = collections.namedtuple("Node", 'point axis label left right')
+
+class KDTree(object):
+    """A tree for nearest neighbor search in a k-dimensional space.
+
+    For information about the implementation, see
+    http://en.wikipedia.org/wiki/Kd-tree
+
+    Usage:
+    objects is an iterable of (co, index) tuples (so MeshVertex is useable)
+    k is the number of dimensions (=3)
+    
+    t = KDTree(k, objects)
+    point, label, distance = t.nearest_neighbor(destination)
+    """
+
+    def __init__(self, k, objects=[]):
+
+        def build_tree(objects, axis=0):
+
+            if not objects:
+                return None
+
+            objects.sort(key=lambda o: o.co[axis])
+            median_idx = len(objects) // 2
+            median_point = objects[median_idx].co
+            median_label = objects[median_idx].index
+
+            next_axis = (axis + 1) % k
+            return Node(median_point, axis, median_label,
+                        build_tree(objects[:median_idx], next_axis),
+                        build_tree(objects[median_idx + 1:], next_axis))
+
+        self.root = build_tree(list(objects))
+        self.size = len(objects)
+
+
+    def nearest_neighbor(self, destination):
+
+        best = [None, None, float('inf')]
+        # state of search: best point found, its label,
+        # lowest distance
+
+        def recursive_search(here):
+
+            if here is None:
+                return

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list