[Bf-extensions-cvs] [8d11170] master: Operator for estimating the maximum number of samples fitting on the ground object.

Lukas Tönne noreply at git.blender.org
Sat Dec 20 14:47:28 CET 2014


Commit: 8d111706e3b1c9a59b981403e84c8f4942bb90ff
Author: Lukas Tönne
Date:   Sat Dec 20 14:45:25 2014 +0100
Branches: master
https://developer.blender.org/rBAC8d111706e3b1c9a59b981403e84c8f4942bb90ff

Operator for estimating the maximum number of samples fitting on the
ground object.

This is based on the optimal circle packing density, which is an upper
bound for the number of samples.

This is a way to avoid gaps in the sampling from insufficient limit for
number of samples.

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

M	object_physics_meadow/meadow.py
M	object_physics_meadow/ui.py
M	object_physics_meadow/util.py

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

diff --git a/object_physics_meadow/meadow.py b/object_physics_meadow/meadow.py
index f910e47..8765dab 100644
--- a/object_physics_meadow/meadow.py
+++ b/object_physics_meadow/meadow.py
@@ -19,6 +19,7 @@
 # <pep8 compliant>
 
 import bpy, os, cProfile, pstats, io
+from math import *
 from mathutils import *
 
 from object_physics_meadow import settings as _settings
@@ -33,16 +34,35 @@ from object_physics_meadow.hierarchical_dart_throw import hierarchical_dart_thro
 
 use_profiling = False
 
+# estimate an upper bound on sample number based on optimal circle packing
+def estimate_max_samples(context, groundob, precision=3):
+    radius = groundob.meadow.sample_distance
+    area_circle = pi * radius*radius
+    
+    mat = groundob.matrix_world
+    bbmin = mat * Vector(tuple(min(p[i] for p in groundob.bound_box) for i in range(3)))
+    bbmax = mat * Vector(tuple(max(p[i] for p in groundob.bound_box) for i in range(3)))
+    area_bounds = (bbmax[0] - bbmin[0]) * (bbmax[1] - bbmin[1])
+    # optimal circle packing area ratio is pi/(2*sqrt(3)) ~= 0.9069
+    # http://en.wikipedia.org/wiki/Circle_packing
+    area_max = area_bounds * pi / (2.0*sqrt(3.0))
+
+    num = area_max / area_circle
+    # round to precision
+    num = int(round_sigfigs(num + 0.5, precision))
+
+    groundob.meadow.max_samples = num
+
 def make_samples(context, gridob, groundob):
     settings = _settings.get(context)
     
     mat = groundob.matrix_world
-    gmin = mat * Vector(tuple(min(p[i] for p in groundob.bound_box) for i in range(3)))
-    gmax = mat * Vector(tuple(max(p[i] for p in groundob.bound_box) for i in range(3)))
+    bbmin = mat * Vector(tuple(min(p[i] for p in groundob.bound_box) for i in range(3)))
+    bbmax = mat * Vector(tuple(max(p[i] for p in groundob.bound_box) for i in range(3)))
     
     # get a sample generator implementation
-    #gen = best_candidate_gen(groundob.meadow.sample_distance, gmin[0], gmax[0], gmin[1], gmax[1])
-    gen = hierarchical_dart_throw_gen(groundob.meadow.sample_distance, groundob.meadow.sampling_levels, gmin[0], gmax[0], gmin[1], gmax[1])
+    #gen = best_candidate_gen(groundob.meadow.sample_distance, bbmin[0], bbmax[0], bbmin[1], bbmax[1])
+    gen = hierarchical_dart_throw_gen(groundob.meadow.sample_distance, groundob.meadow.sampling_levels, bbmin[0], bbmax[0], bbmin[1], bbmax[1])
     
     loc2D = [p[0:2] for p in gen(groundob.meadow.seed, groundob.meadow.max_samples)]
     
diff --git a/object_physics_meadow/ui.py b/object_physics_meadow/ui.py
index 81b96d9..dedf97d 100644
--- a/object_physics_meadow/ui.py
+++ b/object_physics_meadow/ui.py
@@ -85,7 +85,9 @@ class OBJECT_PT_Meadow(Panel):
             sub.prop(meadow, "seed")
             col = sub.column(align=True)
             col.prop(meadow, "sample_distance")
-            col.prop(meadow, "max_samples")
+            sub2 = col.row(align=True)
+            sub2.prop(meadow, "max_samples")
+            sub2.operator("meadow.estimate_max_samples", text="Estimate")
             sub.prop(meadow, "sampling_levels")
             
             if has_samples:
@@ -133,6 +135,23 @@ class MeadowOperatorBase():
         return True, cache_dir
 
 
+class EstimateMaxSamplesOperator(MeadowOperatorBase, Operator):
+    """Estimate an upper bound for the number of samples fitting on the ground object"""
+    bl_idname = "meadow.estimate_max_samples"
+    bl_label = "Estimate Maximum Samples"
+    bl_options = {'REGISTER', 'UNDO'}
+    
+    def execute(self, context):
+        groundob = find_meadow_object(context, 'GROUND')
+        if not groundob:
+            self.report({'ERROR'}, "Could not find meadow Ground object")
+            return {'CANCELLED'}
+        
+        meadow.estimate_max_samples(context, groundob)
+        
+        return {'FINISHED'}
+
+
 class MakeBlobsOperator(MeadowOperatorBase, Operator):
     """Generate Blob objects storing dupli distribution"""
     bl_idname = "meadow.make_blobs"
@@ -265,6 +284,7 @@ def menu_generate_meadow(self, context):
 def register():
     bpy.utils.register_class(OBJECT_PT_Meadow)
     
+    bpy.utils.register_class(EstimateMaxSamplesOperator)
     bpy.utils.register_class(MakeBlobsOperator)
     bpy.utils.register_class(DeleteBlobsOperator)
     bpy.utils.register_class(MakePatchesOperator)
@@ -276,6 +296,7 @@ def register():
 def unregister():
     bpy.utils.unregister_class(OBJECT_PT_Meadow)
     
+    bpy.utils.unregister_class(EstimateMaxSamplesOperator)
     bpy.types.INFO_MT_add.remove(menu_generate_meadow)
     bpy.utils.unregister_class(MakeBlobsOperator)
     bpy.utils.unregister_class(DeleteBlobsOperator)
diff --git a/object_physics_meadow/util.py b/object_physics_meadow/util.py
index d7dafe1..e909006 100644
--- a/object_physics_meadow/util.py
+++ b/object_physics_meadow/util.py
@@ -24,6 +24,16 @@ from math import *
 def ifloor(x):
     return int(x) if x >= 0.0 else int(x) - 1
 
+def iceil(x):
+    return int(x) + 1 if x >= 0.0 else int(x)
+
+# based on http://code.activestate.com/recipes/578114-round-number-to-specified-number-of-significant-di/
+def round_sigfigs(num, sig_figs):
+    if num != 0:
+        return round(num, -int(floor(log10(abs(num))) - (sig_figs - 1)))
+    else:
+        return 0  # Can't take the log of 0
+
 class ObjectSelection():
     def __enter__(self):
         scene = bpy.context.scene



More information about the Bf-extensions-cvs mailing list