CSG failed, exception extern/carve/lib/triangulator.cpp:899

Scripting in Blender with Python, and working on the API

Moderators: jesterKing, stiv

Post Reply
3Dreamer
Posts: 0
Joined: Tue Mar 26, 2013 9:21 am

CSG failed, exception extern/carve/lib/triangulator.cpp:899

Post by 3Dreamer » Thu Jun 13, 2013 6:23 pm

Hi to everyone,


I am using a Boolean modifier through a python script.

During the BOOLEAN Union of two meshes I get the following exception:

CSG failed, exception extern/carve/lib/triangulator.cpp:899 "didn't manage to link up hole!"
Unknown internal error in boolean


As learned by other posts most of the time one can avoid the exception by applying a little spatial rotation to one of the two meshes before applying the modifier, however it would be very useful being able to catch this exception at runtime so that the rotation can be applied automatically.

The problem is that I am not able to catch and handle the exception at runtime in the python script as it is raised by a c++ sublibrary (triangulator.cpp), any idea on how to do this?

Thanks in advance for any attempt to think this through!

stiv
Posts: 0
Joined: Tue Aug 05, 2003 7:58 am
Location: 45N 86W

Post by stiv » Thu Jun 13, 2013 9:33 pm

Only way I know of right offhand is to catch the exception in the Python extension code (C/C++) that calls the C++ module.

3Dreamer
Posts: 0
Joined: Tue Mar 26, 2013 9:21 am

Post by 3Dreamer » Mon Jun 17, 2013 4:41 pm

Hi Stiv thank you for your tip,

do you have any bit of code which does anything vaguely similar to what you are suggesting?
It would be great to have a starting point!

3Dreamer
Posts: 0
Joined: Tue Mar 26, 2013 9:21 am

A partial solution

Post by 3Dreamer » Thu Oct 31, 2013 10:44 am

After few more tries I am still not able to catch the "Unknown internal error in boolean" exception, however I have found a partial solution which may help to avoid the exception.

The following is useful when you already know that applying a boolean operator on two meshes raises the exception OR when you want to make sure that the boolean operator does not generate a corrupted mesh containing non-manifold elements, this often happens when two or more edges/vertices of the input meshes are overlapping.

In this script I have iteratively applied a small random shift along x-y-z for one of the two input meshes, instead a rotation can also be used. The scaler parameter is decisive for obtaining a successful boolean operation as the spatial shift applied to the mesh has to be a small percentage of its overall dimension. In this example I have used boolean UNION but the same process applies to boolean DIFFERENCE and INTERSECTION. If the program still does not return a valid mesh you can always increas the number of iterations (n_attempts) :D

Code: Select all

#########################################################################################
#
# This code takes two input objects which, as they are located, generate a mesh containing
# non-manifold elements when Boolean Union is applied. One of the two objects is randomly
# shifted in space within a user-defined threshold for a number of iterations until the
# Boolean Operator returns a valid mesh (without non-manifold elements).
#
#########################################################################################

import bpy
import bmesh
import random
from random import *

# Boolean_check = 0 Non-Manifold Found / boolean_check = 1 Non-Manifold NOT Found

boolean_check = 1

#How many times it tries to adjust the objects' location 
n_attempts = 50

#This parameter depends on the dimension of the 3D objects

scaler = 0.0000008

#The two objects used for Boolean UNION

object_1 = "Name of first object"

object_2 = "Name of second object"

#Move the objects along the 3 directions
boolean_adjustment_x=[]
boolean_adjustment_y=[]
boolean_adjustment_z=[]

#Prepare random shifts along three axis
for index in range (n_attempts):
    
    boolean_adjustment_x.append(scaler*random())
    boolean_adjustment_y.append(scaler*random())
    boolean_adjustment_z.append(scaler*random())

#Space shift adjustment Loop
for bool_index in range (n_attempts):
    
    print('Iteration number ' +str(bool_index))
    
    print ('Shift in x is ' +str(boolean_adjustment_x[bool_index]))
    print ('Shift in y is ' +str(boolean_adjustment_y[bool_index]))
    print ('Shift in z is ' +str(boolean_adjustment_z[bool_index]))
    
    bpy.context.scene.objects.active = bpy.data.objects[bpy.data.objects.find(object_1)]
    
    bpy.data.objects[bpy.data.objects.find(object_1)].select = True
    
    #Temporary copy of first object
    bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(boolean_adjustment_x[bool_index], boolean_adjustment_y[bool_index], boolean_adjustment_z[bool_index]), "constraint_axis":(True, True, True), "constraint_orientation":'GLOBAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "texture_space":False, "release_confirm":False})
    
    #Attempt Boolean UNION between two objects
    bpy.ops.object.modifier_add(type='BOOLEAN')
    
    bpy.data.objects[bpy.data.objects.find(object_1 +'.001')].modifiers[0].operation='UNION'
    
    bpy.data.objects[bpy.data.objects.find(object_1 +'.001')].modifiers[0].object=bpy.data.objects[bpy.data.objects.find(object_2)]
    
    bpy.ops.object.modifier_apply(modifier='Boolean') 
    
    #-----------------------Non-manifold Check-------------------------------------------
    
    bpy.ops.object.mode_set(mode = 'EDIT')
    
    bpy.ops.mesh.select_all( action='DESELECT' )
    
    bpy.ops.mesh.select_non_manifold(extend=True)
    
    obj=bpy.context.object
    
    bm=bmesh.from_edit_mesh(obj.data)
    
    non_manifolds_counter = 0
    
    #Loop through all vertices and check if they have been selected as non-manifold, if so break the loop (unsuccessful Boolean)
    for v in bm.verts:
        if v.select:
            print('Found a manifold!')
            boolean_check = 0
            non_manifolds_counter = non_manifolds_counter + 1
            break
            
    bpy.ops.object.mode_set(mode = 'OBJECT')
    
    #-------------------------Non-manifolds Check END------------------------------------------
    
    #----------------------------------Check the BOOLEAN flag----------------------------------
    
    #End program if there are NOT non-manifold elements, otherwise keep going with a new shift in x y z...
    
    if (boolean_check == 1 ): 
  
        bool_index = n_attempts
        print("Boolean Union successful!")
        break
    
    else:
        
        #Delete the Unioned mesh with non-manifold elements and re-start with new shift in x y z...
        bpy.ops.object.delete(use_global=True)
        
        bpy.ops.object.select_all(action = 'DESELECT')
        
        boolean_check = 1
I would like to underline that what this script does NOT do is catching the "Unknown internal error in boolean" exception :x

I hope this can avoid the headaches I had with this issue to some of you, happy blending!

The script was tested with Blender 2.68 running on Windows 8 Pro

stiv
Posts: 0
Joined: Tue Aug 05, 2003 7:58 am
Location: 45N 86W

Post by stiv » Thu Oct 31, 2013 4:38 pm

An interesting 'solution' to the problem of ugly triangles and artifacts from performing boolean operations on meshes. I'm impressed!

Post Reply