Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .gitignore

This file was deleted.

7 changes: 0 additions & 7 deletions Makefile

This file was deleted.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ But I realize that not everyone has `git` or an operating system capable of
symlinking.

So, for those that can't: You can simply download the
[meshlint.py](https://raw.github.com/ryanjosephking/meshlint/master/meshlint.py)
[__init__.py](https://raw.github.com/ryanjosephking/meshlint/master/__init__.py)
script directly. (And re-visit that URL for the newest version, later on.)

Installing
----------

The super-awesome way is to directly symlink `meshlint.py` into your [Blender
The super-awesome way is to directly symlink `__init__.py` into your [Blender
Addons
Dir](http://wiki.blender.org/index.php/Doc:2.6/Manual/Introduction/Installing_Blender/DirectoryLayout).
The advantage is that the previous section's `git pull` will download the
Expand All @@ -82,7 +82,7 @@ Addon...` screen.")
Hit `Ctrl+Alt+u` to load up the User Preferences (I always use the keystroke
for this because of the occasional time where you miss, using the `File` menu,
and click `Save User Settings`. Click the `Install Addon...` button at the
bottom, then navigate to your `meshlint.py` script.
bottom, then navigate to your `__init__.py` script.

![The Enable Checkbox](meshlint/raw/master/img/enable-checkbox.png "The Enable
checkbox.")
Expand Down
110 changes: 87 additions & 23 deletions meshlint.py → __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

bl_info = {
"name": "MeshLint: Like Spell-checking for your Meshes",
"author": "rking",
"author": "rking (Port to 2.80 Sav Martin)",
"version": (1, 0),
"blender": (2, 6, 3),
"blender": (2, 80, 0),
"location": "Object Data properties > MeshLint",
"description": "Check objects for: Tris / Ngons / Nonmanifoldness / etc",
"warning": "",
Expand Down Expand Up @@ -169,19 +169,46 @@ def check_interior_faces(self): # translated from editmesh_select.c
bad['faces'].append(f.index)
return bad

CHECKS.append({
'symbol': 'three_poles',
'label': '3-edge Poles',
'definition': 'A vertex with 3 edges connected to it. Also known as an N-Pole',
'default': False
})
def check_three_poles(self):
bad = { 'verts': [] }
for v in self.b.verts:
if 3 == len(v.link_edges):
bad['verts'].append(v.index)
return bad

CHECKS.append({
'symbol': 'five_poles',
'label': '5-edge Poles',
'definition': 'A vertex with 5 edges connected to it. Also known as an E-Pole',
'default': False
})

def check_five_poles(self):
bad = {'verts': [] }
for v in self.b.verts:
if 5 == len(v.link_edges):
bad['verts'].append(v.index)
return bad

CHECKS.append({
'symbol': 'sixplus_poles',
'label': '6+-edge Poles',
'definition': 'A vertex with 6 or more edges connected to it. Generally this is not something you want, but since some kinds of extrusions will legitimately cause such a pole (imagine extruding each face of a Cube outward, the inner corners are rightful 6+-poles). Still, if you don\'t know for sure that you want them, it is good to enable this',
'default': False
'default': True
})

def check_sixplus_poles(self):
bad = { 'verts': [] }
for v in self.b.verts:
if 5 < len(v.link_edges):
bad['verts'].append(v.index)
return bad

# [Your great new idea here] -> Tell me about it: [email protected]

# ...plus the 'Default Name' check.
Expand All @@ -201,15 +228,27 @@ def select_indices(self, elemtype, indices):
print("MeshLint says: Huh?? → elemtype of %s." % elemtype)

def select_vert(self, index):
ob = bpy.context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
bm.verts.ensure_lookup_table() #sav
self.b.verts[index].select = True

def select_edge(self, index):
ob = bpy.context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
bm.edges.ensure_lookup_table() #sav
edge = self.b.edges[index]
edge.select = True
for each in edge.verts:
self.select_vert(each.index)

def select_face(self, index):
ob = bpy.context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
bm.faces.ensure_lookup_table() #sav
face = self.b.faces[index]
face.select = True
for each in face.edges:
Expand Down Expand Up @@ -343,16 +382,17 @@ def poll(cls, context):

def execute(self, context):
if MeshLintVitalizer.is_live:
bpy.app.handlers.scene_update_post.remove(global_repeated_check)
bpy.app.handlers.depsgraph_update_post.remove(global_repeated_check) #sav
MeshLintVitalizer.is_live = False
else:
bpy.app.handlers.scene_update_post.append(global_repeated_check)
bpy.app.handlers.depsgraph_update_post.append(global_repeated_check) #sav
MeshLintVitalizer.is_live = True
return {'FINISHED'}


def activate(obj):
bpy.context.scene.objects.active = obj
# bpy.context.scene.objects.active = obj #sav
bpy.context.view_layer.objects.active = obj


class MeshLintObjectLooper:
Expand Down Expand Up @@ -381,7 +421,7 @@ def examine_all_selected_meshes(self):
self.troubled_meshes.append(obj)
priorities = [self.original_active] + self.troubled_meshes
for obj in priorities:
if obj.select:
if obj.select_get:
activate(obj)
break
self.handle_troubled_meshes()
Expand Down Expand Up @@ -436,7 +476,7 @@ def handle_troubled_meshes(self):
if not obj in self.troubled_meshes:
obj.select = False

class MeshLintControl(bpy.types.Panel):
class MESH_PT_MeshLintControl(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = 'data'
Expand Down Expand Up @@ -493,14 +533,14 @@ def add_criticism(self, layout, context):
label = depluralize(count=count, string=label)
reward = 'ERROR'
col.row().label(text=label, icon=reward)
name_crits = MeshLintControl.build_object_criticisms(
name_crits = MESH_PT_MeshLintControl.build_object_criticisms(
bpy.context.selected_objects, total_problems)
for crit in name_crits:
col.row().label(crit)
col.row().label(text=crit)

def add_toggle_buttons(self, layout, context):
col = layout.column()
col.row().label('Toggle:')
col.row().label(text='Toggle:')
for lint in MeshLintAnalyzer.CHECKS:
prop_name = lint['check_prop']
is_enabled = getattr(context.scene, prop_name)
Expand All @@ -519,10 +559,10 @@ def add_crit(crit):
criticisms.append('...%s "%s" %s.' % (
conjunction, obj.name, crit))
for obj in objects:
if MeshLintControl.has_unapplied_scale(obj.scale):
if MESH_PT_MeshLintControl.has_unapplied_scale(obj.scale):
add_crit('has an unapplied scale')
already_complained = True
if MeshLintControl.is_bad_name(obj.name):
if MESH_PT_MeshLintControl.is_bad_name(obj.name):
add_crit('is not a great name')
already_complained = True
return criticisms
Expand Down Expand Up @@ -580,20 +620,20 @@ class TestControl(unittest.TestCase):
def test_scale_application(self):
for bad in [ [0,0,0], [1,2,3], [1,1,1.1] ]:
self.assertEqual(
True, MeshLintControl.has_unapplied_scale(bad),
True, MESH_PT_MeshLintControl.has_unapplied_scale(bad),
"Unapplied scale: %s" % bad)
self.assertEqual(
False, MeshLintControl.has_unapplied_scale([1,1,1]),
False, MESH_PT_MeshLintControl.has_unapplied_scale([1,1,1]),
"Applied scale (1,1,1)")

def test_bad_names(self):
for bad in [ 'Cube', 'Cube.001', 'Sphere.123' ]:
self.assertEqual(
True, MeshLintControl.is_bad_name(bad),
True, MESH_PT_MeshLintControl.is_bad_name(bad),
"Bad name: %s" % bad)
for ok in [ 'Whatever', 'NumbersOkToo.001' ]:
self.assertEqual(
False, MeshLintControl.is_bad_name(ok),
False, MESH_PT_MeshLintControl.is_bad_name(ok),
"OK name: %s" % ok)


Expand Down Expand Up @@ -700,7 +740,7 @@ def __init__(self, name, scale=Vector([1,1,1])):

class TestUI(unittest.TestCase):
def test_complaints(self):
f = MeshLintControl.build_object_criticisms
f = MESH_PT_MeshLintControl.build_object_criticisms
self.assertEqual([], f([], 0), 'Nothing selected')
self.assertEqual(
[],
Expand Down Expand Up @@ -827,17 +867,41 @@ def run(self, test):
this condition.""")



classes = (
# QuietTestRunner,
# QuietOnSuccessTestResult,
# TestUI,MockBlenderObject,
# TestAnalysis,
# TestUtilities,
# TestControl,
MESH_PT_MeshLintControl,
MeshLintObjectDeselector,
MeshLintSelector,
# MeshLintObjectLooper,
MeshLintVitalizer,
# MeshLintContinuousChecker,
# MeshLintAnalyzer
)


def register():
bpy.utils.register_module(__name__)
from bpy.utils import register_class
for cls in classes:
register_class(cls)




def unregister():
bpy.utils.unregister_module(__name__)
from bpy.utils import unregister_class

for cls in classes:
unregister_class(cls)

if __name__ == '__main__':
register()

if __name__ == "__main__":
register()
except:
# OK, I totally don't get why this is necessary. But otherwise I am not
# seeing error text. Causes the extra indent over all above code. =(
Expand Down
Loading