Thanks Guillaum.
Your example put me on the right path.
I have made a few changes and put it in a test script for Blender 2.5.
It doesn’t have the range function so it will only remove verts that are in exactly the same position but this is fine for what I want.
It seems to be fast enough for my needs.
I hope this is useful to other people.
# --------------------------------------------------------------------------
# Test Remove Doubles.py
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2010: Aaron Keith
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import bpy
# next two utility functions are stolen from import_obj.py
def unpack_list(list_of_tuples):
l = []
for t in list_of_tuples:
l.extend(t)
return l
def unpack_face_list(list_of_tuples):
l = []
for t in list_of_tuples:
face = [i for i in t]
if len(face) != 3 and len(face) != 4:
raise RuntimeError("{0} vertices in face.".format(len(face)))
# rotate indices if the 4th is 0
if len(face) == 4 and face[3] == 0:
face = [face[3], face[0], face[1], face[2]]
if len(face) == 3:
face.append(0)
l.extend(face)
return l
#Remove Doubles takes a list on Verts and a list of Faces and
#removes the doubles, much like Blender does in edit mode.
#It doesn’t have the range function so it will only remove
#verts that are in exactly the same position. The function
#is useful because you can perform a “Remove Doubles” with out
#having to enter Edit Mode. Having to enter edit mode has the
#disadvantage of not being able to interactively change the properties.
def RemoveDoubles(verts,faces):
# print('verts')
# for i in verts:
# print(i)
# print('faces')
# for i in faces:
# print(i)
new_verts = []
new_faces = []
dict_verts = {}
for face in faces:
new_face = []
for face in face:
co = tuple(verts[face])
if co not in dict_verts:
dict_verts[co] = len(dict_verts)
new_verts.append(co)
if dict_verts[co] not in new_face:
new_face.append(dict_verts[co])
if len(new_face) == 3 or len(new_face) == 4:
new_faces.append(new_face)
# print('new verts')
# for i in new_verts:
# print(i)
# print('new faces')
# for i in new_faces:
# print(i)
return new_verts,new_faces
def Create_Mesh(context):
# 1------2
# |\ / |
# | \ / |
# | 4 |
# | / \ |
# |/ \|
# 0------3
#
# 0 = [0.0, 0.0, 0.0]
# 1 = [0.0, 1.0, 0.0]
# 2 = [1.0, 1.0, 0.0]
# 3 = [1.0, 0.0, 0.0]
# 4 = [0.5,0.5,1.0]
verts = []
faces = []
verts += [[0.0, 0.0, 0.0] , [0.0, 1.0, 0.0],[1.0, 1.0, 0.0],[1.0, 0.0, 0.0]]
faces += [[0, 1, 2, 3]] #0 1 2 3
offset = len(verts)
verts += [[0.0, 0.0, 0.0],[1.0, 0.0, 0.0],[0.5,0.5,1.0]]
faces += [[offset+0,offset+1,offset+2]] #0 3 4
offset = len(verts)
verts += [[1.0, 0.0, 0.0],[1.0, 1.0, 0.0],[0.5,0.5,1.0]]
faces += [[offset+0,offset+1,offset+2]] # 3 2 4
offset = len(verts)
verts += [[1.0, 1.0, 0.0],[0.0, 1.0, 0.0],[0.5,0.5,1.0]]
faces += [[offset+0,offset+1,offset+2]] # 2 1 4
offset = len(verts)
verts += [[0.0, 1.0, 0.0],[0.0, 0.0, 0.0],[0.5,0.5,1.0],[0.5,0.5,1.0]] #4 points with 2 of them are the same
faces += [[offset+0,offset+1,offset+2,offset+3]] # 1 0 4 4
offset = len(verts)
verts += [[0.5,0.5,1.0],[0.5,0.5,1.0],[0.5,0.5,1.0]] #3 points all of them the same
faces += [[offset+0,offset+1,offset+2]] # 4 4 4
offset = len(verts)
verts += [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0],[0.5,0.5,1.0],[0.5,0.5,1.0]] #4 points, 2 pairs are the same
faces += [[offset+0,offset+1,offset+2,offset+3]] # 0 0 4 4
print('Mesh verts')
for i in verts:
print(i)
print('Mesh faces')
for i in faces:
print(i)
verts, faces = RemoveDoubles(verts,faces)
print('Mesh verts after Remove Doubles')
for i in verts:
print(i)
print('Mesh faces after Remove Doubles')
for i in faces:
print(i)
mesh = bpy.data.meshes.new("Test")
mesh.add_geometry((len(verts)), 0, int(len(faces)))
mesh.verts.foreach_set("co", unpack_list(verts))
mesh.faces.foreach_set("verts_raw", unpack_face_list(faces))
scene = context.scene
# ugh
for ob in scene.objects:
ob.selected = False
mesh.update()
ob_new = bpy.data.objects.new("Test_ob", mesh)
scene.objects.link(ob_new)
ob_new.selected = True
obj_act = scene.objects.active
class ObjectButtonsPanel(bpy.types.Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_label = "Remove Doubles Test V1.00"
def draw_header(self, context):
layout = self.layout
layout.label(text="", icon='PLUGIN')
def draw(self,context):
layout = self.layout
row = layout.row()
row.operator("custom.Create_Button")
class CUSTOM_OT_Create_Button(bpy.types.Operator):
bl_idname = "CUSTOM_OT_Create_Button"
bl_label = "Create"
__doc__ = "Create Test"
def invoke(self, context, event):
Create_Mesh(context)
return('FINISHED')
def register():
bpy.types.register(ObjectButtonsPanel)
bpy.types.register(CUSTOM_OT_Create_Button)
def unregister():
bpy.types.unregister(ObjectButtonsPanel)
bpy.types.unregister(CUSTOM_OT_Create_Button)
if __name__ == "__main__":
register()