[Bf-extensions-cvs] [d03fdff] master: Script to apply color to objects based on rules

Campbell Barton noreply at git.blender.org
Sat Nov 8 18:38:53 CET 2014


Commit: d03fdffd8d92c8a15688702466f1886c0d7a3e76
Author: Campbell Barton
Date:   Sat Nov 8 18:25:58 2014 +0100
Branches: master
https://developer.blender.org/rBACd03fdffd8d92c8a15688702466f1886c0d7a3e76

Script to apply color to objects based on rules

use with gooseberry branch to quickly setup wire color.

Options are:
- name (regex or simple match)
- material
- group
- layer
- expression (Python expression)

Rules can mix colors so its possible to have useful results where there is overlap between rules.
(especially groups & layers where an object can be in multiple)

===================================================================

A	object_color_rules.py

===================================================================

diff --git a/object_color_rules.py b/object_color_rules.py
new file mode 100644
index 0000000..d58c161
--- /dev/null
+++ b/object_color_rules.py
@@ -0,0 +1,484 @@
+# ***** 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 LICENCE BLOCK *****
+
+bl_info = {
+    "name": "Object Color Rules",
+    "author": "Campbell Barton",
+    "version": (0, 0, 1),
+    "blender": (2, 73, 0),
+    "location": "Properties > Object Buttons",
+    "description": "Rules for assigning object color (used for wireframe colors).",
+    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
+                "Scripts/Object/Color_Rules",
+    "category": "Object",
+    }
+
+
+def test_name(rule, needle, haystack):
+    # TODO, compile expression for re-use
+    if rule.use_match_regex:
+        import re
+        return (re.match(needle, haystack) is not None)
+    else:
+        return (needle in haystack)
+
+
+class rule_test:
+    __slots__ = ()
+
+    def __new__(cls, *args, **kwargs):
+        raise RuntimeError("%s should not be instantiated" % cls)
+
+    @staticmethod
+    def NAME(obj, rule, cache):
+        match_name = rule.match_name
+        return test_name(rule, match_name, obj.name)
+
+    def DATA(obj, rule, cache):
+        match_name = rule.match_name
+        obj_data = obj.data
+        if obj_data is not None:
+            return test_name(rule, match_name, obj_data.name)
+        else:
+            return False
+
+    @staticmethod
+    def GROUP(obj, rule, cache):
+        if not cache:
+            match_name = rule.match_name
+            objects = {o for g in bpy.data.groups if test_name(rule, match_name, g.name) for o in g.objects}
+            cache["objects"] = objects
+        else:
+            objects = cache["objects"]
+
+        return obj in objects
+
+    @staticmethod
+    def MATERIAL(obj, rule, cache):
+        match_name = rule.match_name
+        materials = getattr(obj.data, "materials", None)
+
+        return ((materials is not None) and
+                (any((test_name(rule, match_name, m.name) for m in materials if m is not None))))
+
+    @staticmethod
+    def LAYER(obj, rule, cache):
+        match_layers = rule.match_layers[:]
+        obj_layers = obj.layers[:]
+
+        return any((match_layers[i] and obj_layers[i]) for i in range(20))
+
+    @staticmethod
+    def TYPE(obj, rule, cache):
+        return (obj.type == rule.match_object_type)
+
+    @staticmethod
+    def EXPR(obj, rule, cache):
+        if not cache:
+            match_expr = rule.match_expr
+            expr = compile(match_expr, rule.name, 'eval')
+
+            namespace = {}
+            namespace.update(__import__("math").__dict__)
+
+            cache["expr"] = expr
+            cache["namespace"] = namespace
+        else:
+            expr = cache["expr"]
+            namespace = cache["namespace"]
+
+        try:
+            return bool(eval(expr, {}, {"self": obj}))
+        except:
+            import traceback
+            traceback.print_exc()
+            return False
+
+
+class rule_draw:
+    __slots__ = ()
+
+    def __new__(cls, *args, **kwargs):
+        raise RuntimeError("%s should not be instantiated" % cls)
+
+    @staticmethod
+    def _generic_match_name(layout, rule):
+        layout.label("Match Name:")
+        row = layout.row(align=True)
+        row.prop(rule, "match_name", text="")
+        row.prop(rule, "use_match_regex", text="", icon='SORTALPHA')
+
+    @staticmethod
+    def NAME(layout, rule):
+        rule_draw._generic_match_name(layout, rule)
+
+    @staticmethod
+    def DATA(layout, rule):
+        rule_draw._generic_match_name(layout, rule)
+
+    @staticmethod
+    def GROUP(layout, rule):
+        rule_draw._generic_match_name(layout, rule)
+
+    @staticmethod
+    def MATERIAL(layout, rule):
+        rule_draw._generic_match_name(layout, rule)
+
+    @staticmethod
+    def TYPE(layout, rule):
+        row = layout.row()
+        row.prop(rule, "match_object_type")
+
+    @staticmethod
+    def LAYER(layout, rule):
+        row = layout.row()
+        row.prop(rule, "match_layers")
+
+    @staticmethod
+    def EXPR(layout, rule):
+        col = layout.column()
+        col.label("Scripted Expression:")
+        col.prop(rule, "match_expr", text="")
+
+
+def object_colors_calc(rules, objects):
+    from mathutils import Color
+
+    rules_cb = [getattr(rule_test, rule.type) for rule in rules]
+    rules_blend = [(1.0 - rule.factor, rule.factor) for rule in rules]
+    rules_color = [Color(rule.color) for rule in rules]
+    rules_cache = [{} for i in range(len(rules))]
+    rules_inv = [rule.use_invert for rule in rules]
+
+    for obj in objects:
+        is_set = False
+        obj_color = Color(obj.color[0:3])
+
+        for (rule, test_cb, color, blend, cache, use_invert) \
+             in zip(rules, rules_cb, rules_color, rules_blend, rules_cache, rules_inv):
+
+            if test_cb(obj, rule, cache) is not use_invert:
+                if is_set is False:
+                    obj_color = color
+                else:
+                    # prevent mixing colors loosing saturation
+                    obj_color_s = obj_color.s
+                    obj_color = (obj_color * blend[0]) + (color * blend[1])
+                    obj_color.s = (obj_color_s * blend[0]) + (color.s * blend[1])
+
+                is_set = True
+
+        if is_set:
+            obj.show_wire_color = True
+            obj.color[0:3] = obj_color
+
+
+def object_colors_select(rule, objects):
+    cache = {}
+
+    rule_type = rule.type
+    test_cb = getattr(rule_test, rule_type)
+
+    for obj in objects:
+        obj.select = test_cb(obj, rule, cache)
+
+
+def object_colors_rule_validate(rule, report):
+    rule_type = rule.type
+
+    if rule_type in {'NAME', 'GROUP', 'MATERIAL'}:
+        if rule.use_match_regex:
+            import re
+            try:
+                re.compile(rule.match_name)
+            except Exception as e:
+                report({'ERROR'}, "Rule %r: %s" % (rule.name, str(e)))
+                return False
+
+    elif rule_type == 'EXPR':
+        try:
+            compile(rule.match_expr, rule.name, 'eval')
+        except Exception as e:
+            report({'ERROR'}, "Rule %r: %s" % (rule.name, str(e)))
+            return False
+
+    return True
+
+
+
+import bpy
+from bpy.types import (
+        Operator,
+        Panel,
+        UIList,
+        )
+from bpy.props import (
+        StringProperty,
+        BoolProperty,
+        IntProperty,
+        FloatProperty,
+        EnumProperty,
+        CollectionProperty,
+        BoolVectorProperty,
+        FloatVectorProperty,
+        )
+
+
+class OBJECT_PT_color_rules(Panel):
+    bl_label = "Color Rules"
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "object"
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+
+        # Rig type list
+        row = layout.row()
+        row.template_list(
+                "OBJECT_UL_color_rule", "color_rules",
+                scene, "color_rules",
+                scene, "color_rules_active_index")
+
+        col = row.column()
+        colsub = col.column(align=True)
+        colsub.operator("object.color_rules_add", icon='ZOOMIN', text="")
+        colsub.operator("object.color_rules_remove", icon='ZOOMOUT', text="")
+
+        colsub = col.column(align=True)
+        colsub.operator("object.color_rules_move", text="", icon='TRIA_UP').direction = -1
+        colsub.operator("object.color_rules_move", text="", icon='TRIA_DOWN').direction = 1
+
+        colsub = col.column(align=True)
+        colsub.operator("object.color_rules_select", text="", icon='RESTRICT_SELECT_OFF')
+
+        if scene.color_rules:
+            index = scene.color_rules_active_index
+            rule = scene.color_rules[index]
+
+            box = layout.box()
+            row = box.row(align=True)
+            row.prop(rule, "name", text="")
+            row.prop(rule, "type", text="")
+            row.prop(rule, "use_invert", text="", icon='ARROW_LEFTRIGHT')
+
+            draw_cb = getattr(rule_draw, rule.type)
+            draw_cb(box, rule)
+
+            row = layout.split(0.75, align=True)
+            props = row.operator("object.color_rules_assign", text="Assign Selected")
+            props.use_selection = True
+            props = row.operator("object.color_rules_assign", text="All")
+            props.use_selection = False
+
+
+class OBJECT_UL_color_rule(UIList):
+    def draw_item(self, context, layout, data, rule, icon, active_data, active_propname, index):
+        # assert(isinstance(rule, bpy.types.ShapeKey))
+        # scene = active_data
+        split = layout.split(0.5)
+        row = split.split(align=False)
+        row.label(text="%s (%s)" % (rule.name, rule.type.lower()))
+        split = split.split(0.7)
+        split.prop(rule, "factor", text="", emboss=False)
+        split.prop(rule, "color", text="")
+
+
+class OBJECT_OT_color_rules_assign(Operator):
+    """Assign colors to objects based on user rules"""
+    bl_idname = "object.color_rules_assign"
+    bl_label = "Assign Colors"
+    bl_options = {'UNDO'}
+
+    use_selection = BoolProperty(
+            name="Selected",
+            description="Apply to selected (otherwise all objects in the scene)",
+            default=True,
+            )
+    def execute(self, context):
+        scene = context.scene
+
+        if self.use_selection:
+          

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list