Results 1 to 17 of 17

Thread: Help needed: Boolean Union of many objects

  1. #1

    Help needed: Boolean Union of many objects

    Hello, I have to Boolean Union ca. 150 objects. I have code (below) that works very well on lists of 10-20 selected objects. But if the object count is higher, then Blender calculates forever. Therefor I would like to split the 150-object-list into ca. 10 15-object-lists. Only a pretty small modification of the code below is needed - how can I do this best please? Many thanks!

    Here is the code I have already:


    ##START “UNION OF SELECTED OBJECTS”:
    sce = bpy.context.scene
    myobjectlistlength = len(bpy.context.selected_objects)
    bpy.context.selected_objects[0].name
    myobjectlistlength
    for index in range(0, myobjectlistlength):
    print (index)
    bpy.context.selected_objects[index].name

    originalunionobject = sce.objects.get(bpy.context.selected_objects[0].name)
    originalunionobject_name = bpy.context.selected_objects[0].name
    mymodifier = originalunionobject.modifiers.new('mymodifier', 'BOOLEAN')
    mymodifier.operation = 'UNION'
    nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
    mymodifier.object = nextobject
    bpy.context.scene.objects.active = originalunionobject
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="mymodifier")
    sce.objects.unlink(nextobject)

    for index in range(0, myobjectlistlength-2):
    print (index)
    sce = bpy.context.scene
    ##we always just retrieve the new next element with index 1, because the list gets
    ##shorter and shorter with each new union:
    bpy.context.selected_objects[1].name
    myobjectlistlength
    index+1
    mymodifier = originalunionobject.modifiers.new('mymodifier', 'BOOLEAN')
    mymodifier.operation = 'UNION'
    nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
    mymodifier.object = nextobject
    bpy.context.scene.objects.active = originalunionobject
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="mymodifier")
    sce.objects.unlink(nextobject)
    ##END “UNION OF SELECTED OBJECTS”



  2. #2
    Member batFINGER's Avatar
    Join Date
    Jun 2007
    Location
    Lochiel NSW Australia
    Posts
    1,857
    Hi chrissie,

    to markup code in the forum wrap it in [code][/code] tags.

    The object.join operator may be a simpler way to do this.

    Code:
    import bpy
    
    
    # join them
    bpy.ops.object.join()

    afterwards you may wish to remove doubles with

    Code:
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.mesh.remove_doubles()



  3. #3
    Member gregzaal's Avatar
    Join Date
    Jun 2010
    Location
    Johannesburg
    Posts
    2,192
    @batFINGER - he wants boolean union, not just simply joining objects.

    @chrissie - without wraping the code in the tags batFINGER mentions, we cant tell where the indents are and thus cant help. Or you could upload to pasteall.org.

    I've been wanting something like this for a long time, but been to lazy to try code it



  4. #4
    Member batFINGER's Avatar
    Join Date
    Jun 2007
    Location
    Lochiel NSW Australia
    Posts
    1,857
    Originally Posted by gregzaal View Post
    @batFINGER - he wants boolean union, not just simply joining objects.

    @chrissie - without wraping the code in the tags batFINGER mentions, we cant tell where the indents are and thus cant help. Or you could upload to pasteall.org.

    I've been wanting something like this for a long time, but been to lazy to try code it
    I'm aware of the difference @gregzaal.

    I'm Not sure how much of an improvement would be achieved by splitting the list into smaller parts. If there is no intersection then join would be alot quicker to achieve the same result. Even changing the originally posted code with a simple bounding box intersection test to either join or add and apply modifier would speed it up IMO. Splitting the list into non intersecting sets, joining then using union would be my suggestion. Surely each and all of the 150 objects don't intersect each other.



  5. #5
    Member gregzaal's Avatar
    Join Date
    Jun 2010
    Location
    Johannesburg
    Posts
    2,192
    Great idea. Best would be to try join all the non-intersecting objects into just a few objects first, only then doing the boolean.



  6. #6

    Need for multiple boolean connection script or process help.

    I too have this need.
    What I have is a bunch (appx 200) of spheres and cylinders that I need to boolean together (like a molecule). Unfortunately I cannot join them and boolean them because they are randomly indexed.
    here's a picture (and a closeup) for example:

    smallsphere1.PNG smallsphere1 closeup.PNG

    Sorry for the dreadful lighting. So each cylinder and each sphere are disconnected objects, and the cylinders "penetrate" into the spheres. I have tried some code snippets suggested by others but none comes close.

    What I'm thinking is to somehow, starting with any randomly chosen sphere, to sequentially boolean every connecting cylinder, then proceed to iteratively repeat this process until everything's connected. Unfortunately since i'm new to blender scripting and python i'm crazy stuck.

    Any help appreciated.



  7. #7
    Member
    Join Date
    Dec 2011
    Location
    Germany
    Posts
    3,991
    hm... if there was a way to add vertices on edges at intersection points, one could do that and then select only the outside vertices, invert selection and delete verts



  8. #8
    Hi! Here is what I created / used ("quick and dirty", but it works for me):


    Code:
    ##START “UNION OF SELECTED OBJECTS”:
    sce = bpy.context.scene
    myobjectlistlength = len(bpy.context.selected_objects)
    bpy.context.selected_objects[0].name
    myobjectlistlength
    for index in range(0, myobjectlistlength): 
      print (index)
       bpy.context.selected_objects[index].name
    
    originalunionobject = sce.objects.get(bpy.context.selected_objects[0].name)
    originalunionobject_name = bpy.context.selected_objects[0].name
    mymodifier = originalunionobject.modifiers.new('mymodifier', 'BOOLEAN')
    mymodifier.operation = 'UNION'
    nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
    mymodifier.object = nextobject
    bpy.context.scene.objects.active = originalunionobject
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="mymodifier")
    sce.objects.unlink(nextobject)
    
    # for index in range(0, 10):
    for index in range(0, myobjectlistlength-2):  
       print (index)  
       sce = bpy.context.scene
    ##we always just retrieve the new next element with index 1, because the list gets
    ##shorter and shorter with each new union:
       bpy.context.selected_objects[1].name
       myobjectlistlength
       index+1
       mymodifier = originalunionobject.modifiers.new('mymodifier', 'BOOLEAN')
       mymodifier.operation = 'UNION'
       nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
       mymodifier.object = nextobject
       bpy.context.scene.objects.active = originalunionobject
       bpy.ops.object.modifier_apply(apply_as='DATA', modifier="mymodifier")
       sce.objects.unlink(nextobject)
    ##END  “UNION OF SELECTED OBJECTS
    You first select all objects to boolean union.
    Then execute the code in the python console.

    I once had a memory problem when I wanted to boolean union too many objects in one go.
    I created a variant of the code which 1st unioned in chunks of 15, then unioned those.
    Let me know if you need this.


    Let me know if you have questions.
    Last edited by chrissie; 09-Apr-13 at 10:01.



  9. #9
    Ahoi,

    got it triggered out how to Union boolean many objects:

    #!BPY
    """
    Name: 'Muli Boolean Union'
    Blender: 242
    Group: 'Misc'
    Tooltip: 'trying'
    """
    from Blender import *
    from Blender import Draw, Scene, Object
    from Blender.Mathutils import Rand
    # runs through all objects and boolean:union them together
    def supb(scn, sel):
    i = 0
    for objss in sel:
    if i == 0:
    objFirst = objss
    i = 1
    else: # i == 1
    if i == 1:
    objSecond = objss
    i = 2

    # adding modifier
    mods = objFirst.modifiers # adding a modifier
    mod = mods.append(Modifier.Types.BOOLEAN) # with boolean
    mod[Modifier.Settings.OPERATION] = 1 # and union

    # doing the modifier
    mod[Modifier.Settings.OBJECT] = objSecond # adding the element to the modifier
    objFirst.makeDisplayList() # doing the modifier

    # deleting the old two
    # scn.unlink( objFirst )
    scn.unlink( objSecond )
    else:
    i = 3
    Window.RedrawAll() #??

    def main():
    scn = Scene.GetCurrent()
    if not scn.objects.context:
    return

    sel = scn.objects.context
    objects = [ob for ob in scn.objects.context]
    Count = len(objects)
    # i = 0
    # while i < 10:
    # i = i + 1
    f = Count
    for i in range(0, f):
    supb( scn, sel )
    sel = scn.objects.context


    Window.RedrawAll()

    if __name__ == '__main__':
    main()


    -------------------

    also here is a script, which Looks good...was not working with me:

    http://www.mediafire.com/view/7d8kv9...ion+script.txt

    have fun



  10. #10
    This question is old but maybe some people still want this and end up here.

    A quite easy, non scripting solution is:

    1. join all meshes you want to union
    2. draw a large cube around it, that contains all your joined meshes.
    3. apply a boolean operator "intersect" on this cube and your joined mesh

    Seems to work!



  11. #11
    Originally Posted by raymondnijssen View Post
    This question is old but maybe some people still want this and end up here.

    A quite easy, non scripting solution is:

    1. join all meshes you want to union
    2. draw a large cube around it, that contains all your joined meshes.
    3. apply a boolean operator "intersect" on this cube and your joined mesh

    Seems to work!

    raymondnijssen...you're the best!!!!!!

    I haven't tried it in complex figures but it seems to work perfectly!!!!!! AWESOME



  12. #12
    The idea is really perfect. And I just tried on some complex meshes... it seems that part of the object is missing.
    input.jpgoutput.jpg
    I'll try the script way soon, maybe it won't work either.



  13. #13
    The script way is not working either. Here's my code, it maybe helpful to someone sometime.
    Code:
    loopCategoryNum = [50, 776]
    loopCategory = ["ball", "cylinder"]
    basePath = "E:/Coding/skeleton_code/skeleton_code/bin/Mesh/"
    
    
    for categoryIndex in range(len(loopCategory)):
        loopIndex = int((loopCategoryNum[categoryIndex]-1)/50)
        for i in range(loopIndex+1):
            bpy.ops.import_scene.obj(filepath = basePath + loopCategory[categoryIndex] + str(i*50) + ".obj")
            para1 = bpy.data.objects[loopCategory[categoryIndex] + str(i*50)]
            bpy.context.scene.objects.active = para1
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.tris_convert_to_quads()
            bpy.ops.object.mode_set(mode='OBJECT')
            for j in range(i*50+1,i*50+50):
                if j>=loopCategoryNum[categoryIndex]:
                    break
                bpy.ops.import_scene.obj(filepath = basePath + loopCategory[categoryIndex] + str(j) + ".obj")
                para2 = bpy.data.objects[loopCategory[categoryIndex] + str(j)]
                bpy.context.scene.objects.active = para2
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.tris_convert_to_quads()
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.context.scene.objects.active = para1
                boolean_modifier = para1.modifiers.new('Name', 'BOOLEAN')
                boolean_modifier.operation = 'UNION'
                boolean_modifier.object = para2
                bpy.ops.object.modifier_apply(apply_as='DATA', modifier = 'Name')
                bpy.context.scene.objects.active = para2
                bpy.ops.object.delete()
            #if i!=0:
                #para2 = bpy.data.objects[loopCategory[categoryIndex] + str(i*50-50)]
                #bpy.context.scene.objects.active = para1
                #boolean_modifier = para1.modifiers.new('Name', 'BOOLEAN')
                #boolean_modifier.operation = 'UNION'
                #boolean_modifier.object = para2
                #bpy.ops.object.modifier_apply(apply_as='DATA', modifier = 'Name')
                #bpy.context.scene.objects.unlink(para2)
    The commented code is not working, but I think the problems come from blender's boolean operation itself.
    (I try to manually combine those segments, blender(2.76) tells me it can not excute bool operation)

    update: I come up with a new idea!!! We can first do the "difference boolean operation" between each pair (as the pre processing). To ensure every two segments are not collided.
    Last edited by a120471; 25-Jan-16 at 22:44.



  14. #14
    Originally Posted by tcdoe View Post

    What I'm thinking is to somehow, starting with any randomly chosen sphere, to sequentially boolean every connecting cylinder, then proceed to iteratively repeat this process until everything's connected. Unfortunately since i'm new to blender scripting and python i'm crazy stuck.

    Any help appreciated.
    I realize this is old, but I came across the thread when I need to do the same thing (for a ball and stick molecular model). Taking pieces from other scripts I came up with something that does exactly this. It uses the selected objects so if you start with something that has many objects (I've used it on structures with ~1200 objects imported as VRML2) it can be faster to select it in chunks instead of trying to do it all in one pass. Also, make sure there are no internal objects. PyMol stick representations always put out extra spheres at the end.

    Code:
    import bpy
    import bmesh
    from mathutils.bvhtree import BVHTree
    
    
    def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False):
        """
        Returns a transformed, triangulated copy of the mesh
        """
    
    
        assert(obj.type == 'MESH')
    
    
        if apply_modifiers and obj.modifiers:
            me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False)
            bm = bmesh.new()
            bm.from_mesh(me)
            bpy.data.meshes.remove(me)
        else:
            me = obj.data
            if obj.mode == 'EDIT':
                bm_orig = bmesh.from_edit_mesh(me)
                bm = bm_orig.copy()
            else:
                bm = bmesh.new()
                bm.from_mesh(me)
    
    
        # Remove custom data layers to save memory
        for elem in (bm.faces, bm.edges, bm.verts, bm.loops):
            for layers_name in dir(elem.layers):
                if not layers_name.startswith("_"):
                    layers = getattr(elem.layers, layers_name)
                    for layer_name, layer in layers.items():
                        layers.remove(layer)
    
    
        if transform:
            bm.transform(obj.matrix_world)
    
    
        if triangulate:
            bmesh.ops.triangulate(bm, faces=bm.faces)
    
    
        return bm
    
    
    def bmesh_check_intersect_objects(obj, obj2):
        """
        Check if any faces intersect with the other object
    
    
        returns a boolean
        """
        assert(obj != obj2)
    
    
        # Triangulate
        bm = bmesh_copy_from_object(obj, transform=True, triangulate=True)
        bm2 = bmesh_copy_from_object(obj2, transform=True, triangulate=True)
        intersect = False
        BMT1 = BVHTree.FromBMesh(bm)
        BMT2 = BVHTree.FromBMesh(bm2)
        overlap_pairs = BMT1.overlap(BMT2)
        #print (len(overlap_pairs))
        
        if len(overlap_pairs) > 0:
           intersect = True
        
        return intersect
    
    
       
    
    
    sce = bpy.context.scene
    
    
    myobjectlistlength = len(bpy.context.selected_objects)
    startlist = len(bpy.context.selected_objects)
    i = 0
    
    
    
    
    while i < myobjectlistlength or myobjectlistlength > 1:
      sce.update()
      obj1 = bpy.context.selected_objects[0]
    
    
      for obj2 in bpy.context.selected_objects:
            if obj1.name == obj2.name:
                continue
            #print(obj1.name)
            #print(obj2.name)
            intersect = bmesh_check_intersect_objects(obj1, obj2)
    
    
            if intersect:
               mymodifier = obj1.modifiers.new('mymodifier', 'BOOLEAN')
               mymodifier.operation = 'UNION'
               mymodifier.object = obj2
               bpy.context.scene.objects.active = obj1
               bpy.ops.object.convert(target='MESH')
               sce.objects.unlink(obj2) 
               myobjectlistlength = len(bpy.context.selected_objects)
               print("Objects left to merge: %s" % myobjectlistlength)
                  
               
      i = i+1



  15. #15
    Originally Posted by raymondnijssen View Post
    This question is old but maybe some people still want this and end up here.

    A quite easy, non scripting solution is:

    1. join all meshes you want to union
    2. draw a large cube around it, that contains all your joined meshes.
    3. apply a boolean operator "intersect" on this cube and your joined mesh

    Seems to work!
    This seemed like a great idea, but it didn't work for me. The places where the once individual objects meet don't result in joined vertices after the intersection. This had implications down the road for 3D printing.



  16. #16
    Member gregzaal's Avatar
    Join Date
    Jun 2010
    Location
    Johannesburg
    Posts
    2,192
    There is now an add-on included in Blender by default (2.78): https://wiki.blender.org/index.php/D..._Boolean_Tools

    Or download it here: https://git.blender.org/gitweb/gitwe...olean_tools.py



  17. #17
    Originally Posted by shocksofmighty View Post
    This seemed like a great idea, but it didn't work for me. The places where the once individual objects meet don't result in joined vertices after the intersection. This had implications down the road for 3D printing.
    I actually tried this again, realizing that I hadn't attempted it after removing the fully internal spheres that were in my object. After removing the internal spheres it worked great! Now I'm feeling silly or spending so much time writing that script.



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •