コード例 #1
0
def CreateSketch(sketch_harness_file, sketch_solver_file, data_file, \
  idx_file, primitive_file):
    # Now many bits do we need?
    point_num = sum(1 for line in open(idx_file))
    bits = math.ceil(math.log2(point_num)) + 1
    helper.PrintWithGreenColor('Using %d bits to encode the constraints.' %
                               bits)
    # Generate the first line in the sketch_solver_file.
    first_line = 'pragma options "--fe-fpencoding TO_BACKEND ' \
                 '--bnd-unroll-amnt 32 --bnd-inbits %d ' \
                 '--slv-lightverif";\n' % bits
    f = open(sketch_solver_file, 'w')
    f.write(first_line)
    for line in open(os.path.join(os.environ['CSG_ROOT'], 'sketch', \
      basic_sketch_solver_file)):
        f.write(line)
    f.close()

    f = open(sketch_harness_file, 'w')
    content = '#include "%s"\n' \
              '#include "%s"\n' \
              '\n' \
              '#include "%s"\n' \
              '\n' \
              '@FromFile("%s")\n' \
              'harness void main(int id) {\n' \
              '  check(id);\n' \
              '}\n' % (data_file, primitive_file, \
              os.path.basename(sketch_solver_file), idx_file)
    f.write(content)
    f.close()
コード例 #2
0
ファイル: install.py プロジェクト: mariarzv/inverseCSG
def CheckSketch():
    sketch_result = subprocess.getoutput('sketch')
    # The first line should be something like:
    # SKETCH version 1.7.4
    # The following is not a very robust way to check the version number.
    if 'SKETCH version' not in sketch_result:
        return False
    # Now check version number.
    first_line = sketch_result.splitlines()[0]
    _, _, version_number = first_line.strip().split()
    # Expect to see >= 1.7.4.
    if not CheckVersionNumber(version_number, '1.7.4'):
        return False
    # Now Sketch seems working.
    helper.PrintWithGreenColor('Sketch %s seems successfully installed.' %
                               version_number)
    # Save environment variables into files.
    sketch_loc = subprocess.getoutput('whereis sketch')
    env_variables['CSG_SKETCH'] = sketch_loc.strip().split()[1].strip()
    # Auto-complete paths.
    readline.set_completer_delims(' \t\n;')
    readline.parse_and_bind('tab: complete')
    readline.set_completer(AutoComplete)
    while 'CSG_SKETCH_FRONTEND' not in env_variables:
        sketch_frontend_folder = '/home/runner/work/inverseCSG/inverseCSG/sketch-frontend'
        env_variables['CSG_SKETCH_FRONTEND'] = sketch_frontend_folder
    while 'CSG_SKETCH_BACKEND' not in env_variables:
        sketch_backend_folder = '/home/runner/work/inverseCSG/inverseCSG/sketch-backend'
        env_variables['CSG_SKETCH_BACKEND'] = sketch_backend_folder
    return True
コード例 #3
0
def InstallEigen(root_folder, init=True):
  if init:
    helper.Run('wget http://bitbucket.org/eigen/eigen/get/3.3.4.zip')
    cpp_lib_folder = os.path.join(root_folder, 'cpp', 'lib')
    helper.Run('unzip 3.3.4.zip -d %s' % os.path.join(cpp_lib_folder))
    helper.Run('mv %s %s' % (os.path.join(cpp_lib_folder, \
     'eigen-eigen-5a0156e40feb'), os.path.join(cpp_lib_folder, 'eigen-3.3.4')))
    helper.Run('rm 3.3.4.zip')
    helper.PrintWithGreenColor('Installed Eigen')
コード例 #4
0
def InstallCGAL(build_folder, init=True):
  helper.Run('sudo apt-get install libcgal-dev')
  helper.PrintWithGreenColor('Installed libcgal-dev')
  if init:
    cgal_url = 'https://github.com/CGAL/cgal/releases/download/' \
               'releases%2FCGAL-4.12/CGAL-4.12.zip'
    cgal_file = os.path.join(build_folder, 'cgal.zip')
    urllib.request.urlretrieve(cgal_url, cgal_file)
    helper.Run('unzip -o -q %s -d %s' % (cgal_file, build_folder))
    os.remove(cgal_file)
  # Now you have the source code.
  helper.PrintWithGreenColor('Downloaded and unzipped CGAL 4.12')
  cgal_dir = ''
  for folder_name in os.listdir(build_folder):
    if 'cgal' in folder_name or 'CGAL' in folder_name:
      cgal_dir = os.path.join(build_folder, folder_name)
      break
  # Add cgal_root to the environment variable list.
  env_variables['CGAL_DIR'] = os.environ['CGAL_DIR'] = cgal_dir
コード例 #5
0
def InstallEigen(root_folder, init=True):
    if init:
        # helper.Run('wget http://bitbucket.org/eigen/eigen/get/3.3.4.zip')
        helper.Run(
            'wget https://github.com/eigenteam/eigen-git-mirror/archive/3.3.4.zip'
        )
        cpp_lib_folder = os.path.join(root_folder, 'cpp', 'lib')
        helper.Run('unzip 3.3.4.zip -d %s' % os.path.join(cpp_lib_folder))
        helper.Run('mv %s %s' % (os.path.join(cpp_lib_folder, \
         'eigen-git-mirror-3.3.4'), os.path.join(cpp_lib_folder, 'eigen-3.3.4')))
        helper.Run('rm 3.3.4.zip')
        helper.PrintWithGreenColor('Installed Eigen')
コード例 #6
0
def CheckSketch(build_folder):
  sketch_result = subprocess.getoutput('sketch')
  # The first line should be something like:
  # SKETCH version 1.7.4
  # The following is not a very robust way to check the version number.
  if 'SKETCH version' not in sketch_result:
    return False
  # Now check version number.
  first_line = sketch_result.splitlines()[0]
  _, _, version_number = first_line.strip().split()
  # Expect to see >= 1.7.4.
  if not CheckVersionNumber(version_number, '1.7.4'):
    return False
  # Now Sketch seems working.
  helper.PrintWithGreenColor('Sketch %s seems successfully installed.' %
                       version_number)
  # Save environment variables into files.
  sketch_loc = subprocess.getoutput('whereis sketch')
  env_variables['CSG_SKETCH'] = sketch_loc.strip().split()[1].strip()
  # Auto-complete paths.
  readline.set_completer_delims(' \t\n;')
  readline.parse_and_bind('tab: complete')
  readline.set_completer(AutoComplete)

  # try local first : build/sketch/sketch-frontend
  sketch_frontend_folder = os.path.join(build_folder, 'sketch', 'sketch-frontend')
  if os.path.exists(sketch_frontend_folder):
    env_variables['CSG_SKETCH_FRONTEND'] = sketch_frontend_folder
  sketch_backend_folder = os.path.join(build_folder, 'sketch', 'sketch-backend')
  if os.path.exists(sketch_backend_folder):
    env_variables['CSG_SKETCH_BACKEND'] = sketch_backend_folder

  while 'CSG_SKETCH_FRONTEND' not in env_variables:
    sketch_frontend_folder = input('Tell us the location of sketch-frontend: ') 
    if not os.path.exists(sketch_frontend_folder):
      print('Folder does not exist. Please try again.')
      continue
    env_variables['CSG_SKETCH_FRONTEND'] = sketch_frontend_folder
  while 'CSG_SKETCH_BACKEND' not in env_variables:
    sketch_backend_folder = input('Tell us the location of sketch-backend: ') 
    if not os.path.exists(sketch_backend_folder):
      print('Folder does not exist. Please try again.')
      continue
    env_variables['CSG_SKETCH_BACKEND'] = sketch_backend_folder
  return True
コード例 #7
0
def GetSketch(sketch_harness_file, sketch_output_file, timeout):
    sketch_lib_loc = os.path.join(os.environ['CSG_SKETCH_FRONTEND'], \
      'src/sketchlib/')
    cegis_loc = os.path.join(os.environ['CSG_SKETCH_BACKEND'], \
      'src/SketchSolver/cegis')
    timeout_min = float(timeout) / 60.0
    cmd = 'bash %s -V 10 --fe-inc %s ' \
      '--fe-kill-asserts --fe-output-test --fe-output-dir %s ' \
      '--fe-cegis-path %s %s --fe-timeout %f' % \
      (os.environ['CSG_SKETCH'], \
       sketch_lib_loc, sketch_output_dir + '/', cegis_loc, sketch_harness_file, \
       timeout_min)
    helper.PrintWithGreenColor(cmd)
    output = open(sketch_output_file, 'w')
    return_code = subprocess.call(cmd, stderr = subprocess.STDOUT, \
      stdout = output, shell = True)
    output.close()
    # After testing we figured if timeout the return code is 1 and if it ends
    # normally the return code is 0.
    return return_code == 0
コード例 #8
0
ファイル: install.py プロジェクト: mariarzv/inverseCSG
################################################################################
env_variables = {}

################################################################################
# Beginning of the script.
################################################################################
# Usage: python3 install.py <build folder>
if len(sys.argv) < 2:
    print('Usage: python3 install.py <build_folder>')
    sys.exit(-1)

build_folder = os.path.realpath(sys.argv[1])
root_folder = os.path.dirname(os.path.realpath(sys.argv[0]))
if not os.path.exists(build_folder):
    os.makedirs(build_folder)
helper.PrintWithGreenColor('Build folder created.')

# Add a new environment variable to save the location of the root folder.
env_variables['CSG_ROOT'] = os.environ['CSG_ROOT'] = root_folder

# show LIBC version
helper.RunWithStdout('sudo dpkg -l libc6')

# This may work on Xenial
helper.Run('sudo apt-get update')
helper.Run('sudo apt-get install build-essential ' \
  'software-properties-common -y')
helper.RunWithStdout('sudo apt-get install gcc-snapshot -y')

# Install python dependencies.
helper.RunWithStdout(
コード例 #9
0
def RunSketchPipeline():
    mesh_info = Preprocessing()
    all_pos_points = helper.LoadDataFile(mesh_info['pos_file'])
    vol_pos_points = helper.LoadDataFile(mesh_info['vol_pos_file'])
    all_neg_points = helper.LoadDataFile(mesh_info['neg_file'])
    satisfied_pos = np.zeros((0, 3))

    # Major loop starts here.
    part_file = os.path.join(point_output_dir, 'part_0.data')
    shutil.copy(mesh_info['vol_pos_file'], part_file)
    todo = [part_file]
    solutions = []
    while len(todo) > 0:
        # Pop the first element.
        part_file = todo[0]
        # Extract idx from the file name part_XX.data.
        idx = int(part_file[part_file.rfind('_') + 1:-len('.data')])
        volumes = helper.LoadDataFile(part_file)
        todo = todo[1:]
        print('Attempt to solve part %d...' % idx)

        # Compute the bounding box of volume. Intentionally enlarge it a bit.
        box_min = volumes.min(axis=0) - 0.01
        box_max = volumes.max(axis=0) + 0.01
        prim_roi = EnlargeBoundingBox((box_min[0], box_max[0], box_min[1], \
          box_max[1], box_min[2], box_max[2]), 1.1)

        # Merge volumes to get positive constraints.
        cpp_exe = os.environ['CSG_CPP_EXE']
        new_pos_file = os.path.join(point_output_dir, 'pos_%d.data' % idx)
        helper.Run('%s equiv-class -e %f -i %s -p %s -o %s' % (cpp_exe, eps, \
          part_file, mesh_info['primitive_file'], new_pos_file))

        # Subtract satisfied_pos from pos_idx.data.
        tmp_data_file = os.path.join(point_output_dir, '.tmp_%d.data' % idx)
        helper.SaveDataFile(tmp_data_file, satisfied_pos)
        helper.Run('%s remove-equiv-class -e %f -i %s -o %s -p %s -r %s' % (\
          cpp_exe, eps, new_pos_file, new_pos_file, \
          mesh_info['primitive_file'], tmp_data_file))
        os.remove(tmp_data_file)

        pos_points = helper.LoadDataFile(new_pos_file)
        if pos_points.size == 0:
            helper.PrintWithGreenColor('Part %d has been resolved.' % idx)
            continue
        solution, done = SolveOnePartWithOuterLoop(idx, pos_points, \
          all_neg_points, prim_roi, mesh_info)
        if done:
            helper.PrintWithGreenColor('Part %d is done.' % idx)
            # Generate current solution.
            solutions.append(solution)
            csg_file = os.path.join(csg_output_dir, 'solution_%d.scad' % idx)
            f = open(csg_file, 'w')
            # Enclose this solution with the bounding box.
            x_min, x_max, y_min, y_max, z_min, z_max = mesh_info[
                'bounding_box']
            f.write('intersection() {\n')
            f.write('translate([%f, %f, %f])\n' % (x_min, y_min, z_min))
            f.write('cube(size = [%f, %f, %f], center = false);\n' % \
              (x_max - x_min, y_max - y_min, z_max - z_min))
            f.write('union() {\n')
            for s in solutions:
                f.write(s)
                f.write('\n')
            f.write('}\n')
            f.write('}\n')
            f.close()
            # Check if all point constraints can be satisfied.
            tmp_pos_file = os.path.join(csg_output_dir, '.pos.data')
            tmp_neg_file = os.path.join(csg_output_dir, '.neg.data')
            helper.Run('%s csg-flag -d %s -e %f -i %s -n %s -p %s' % \
                       (cpp_exe, mesh_info['pos_file'], eps, csg_file, \
                        tmp_neg_file, tmp_pos_file))
            satisfied_pos = helper.LoadDataFile(tmp_pos_file)
            unsatisfied_pos = helper.LoadDataFile(tmp_neg_file)
            os.remove(tmp_pos_file)
            os.remove(tmp_neg_file)
            if unsatisfied_pos.size == 0:
                # We have found the solution.
                helper.PrintWithGreenColor('All constraints were satisfied. Result is ' \
                  'in %s.' % csg_file)
                return
        else:
            # Segment the volume.
            point_cloud_seg.SegmentPointCloud(part_file, seg_num, \
              part_file[:-len('.data')])
            # Get the last idx.
            last_part_file = todo[-1] if len(todo) > 0 else part_file
            last_idx = int(last_part_file[last_part_file.rfind('_') + 1 \
              : -len('.data')])
            new_idx = last_idx + 1
            for i in range(seg_num):
                new_part_file = \
                  part_file[:part_file.rfind('_') + 1] + str(new_idx + i) + '.data'
                shutil.copyfile(part_file[:-len('.data')] + '_' + str(i) + '.data' , \
                  new_part_file)
                todo.append(new_part_file)
コード例 #10
0
 def UnsatHandler(command, exit_code):
     if exit_code != unsat_code:
         helper.DefaultExceptionHandle(command, exit_code)
     else:
         helper.PrintWithGreenColor('UNSAT detected.')
コード例 #11
0
def SolveOnePart(idx, all_pos_constraints, all_neg_constraints, primitive_roi, \
  mesh_info):
    # Call this function to solve all_pos_constraints and all_neg_constraints
    # using primitives inside primitive_roi.
    # Returns a string that describes the csg tree, and done to indicate whether
    # the problem is solved.
    # Call Sketch to satisfy pos_constraints and neg_constraints.
    xmin, xmax, ymin, ymax, zmin, zmax = primitive_roi
    helper.PrintWithGreenColor('Part %d, roi (%f, %f, %f, %f, %f, %f)' \
      % (idx, xmin, xmax, ymin, ymax, zmin, zmax))
    print('Constraints: %d positive, %d negative.' % \
      (all_pos_constraints.shape[0], all_neg_constraints.shape[0]))
    # Save them for debugging purposes. They are duplicated in data.sk.
    pos_constraints_file = os.path.join(point_output_dir, 'pos_%d.data' % idx)
    helper.SaveDataFile(pos_constraints_file, all_pos_constraints)
    neg_constraints_file = os.path.join(point_output_dir, 'neg_%d.data' % idx)
    helper.SaveDataFile(neg_constraints_file, all_neg_constraints)

    # Prepare the data file.
    sketch_data_file = os.path.join(sketch_harness_dir, 'data_%d.sk' % idx)
    sketch_idx_file = os.path.join(sketch_harness_dir, 'idx_%d.sk' % idx)
    helper.SavePointToSketch(sketch_data_file, sketch_idx_file, \
      all_pos_constraints, all_neg_constraints)

    # Prepare the primitive file.
    prim_file = os.path.join(point_output_dir,
                             'surface_primitives_%d.prim' % idx)
    unsat_code = 1

    def UnsatHandler(command, exit_code):
        if exit_code != unsat_code:
            helper.DefaultExceptionHandle(command, exit_code)
        else:
            helper.PrintWithGreenColor('UNSAT detected.')

    while True:
        xmin, xmax, ymin, ymax, zmin, zmax = primitive_roi
        helper.Run('%s primitive-local -p %s -o %s -i %s -s %f %f %f %f %f %f' % ( \
          os.environ['CSG_CPP_EXE'], mesh_info['primitive_file'], prim_file, \
          '.dummy.meta', xmin, xmax, ymin, ymax, zmin, zmax))
        # See if the problem is SAT.
        code = helper.Run('%s remove-prim -e %f -i %s -o %s -n %s -p %s -v' % ( \
          os.environ['CSG_CPP_EXE'], eps, prim_file, prim_file, \
          neg_constraints_file, pos_constraints_file), UnsatHandler)
        if code == 0:
            break
        elif code == unsat_code:
            # Try to enlarge the roi.
            if Enclose(primitive_roi, mesh_info['bounding_box']):
                helper.PrintWithRedColor('Roi is already larger than the bounding ' \
                  'box but the problem is still UNSAT. Should never happen.')
                sys.exit(-1)
            helper.PrintWithGreenColor(
                'Enlarge the primitive roi and retry...')
            primitive_roi = EnlargeBoundingBox(primitive_roi, 1.1)
        else:
            # Should never happen.
            helper.PrintWithRedColor('See exit code other than 1. ' \
              'Should never happen.')
            sys.exit(-1)

    # Now the surface primitives are stored in prim_file and all of them are
    # necessary. We can count the number of solid primitives and terminate it
    # early if we are sure the solution is too big for sketch to solve.
    estimated_prim_num = \
      surface_primitive_to_sketch.CountMinimumNumberOfSolidPrimitives(prim_file)
    if estimated_prim_num > max_prim_num:
        # Call segmentation.
        helper.PrintWithRedColor('Problem seems to require a deeper CSG tree. ' \
                                 'Call segmentation.')
        return '', False

    prim_sketch_file = os.path.join(sketch_harness_dir, \
      'primitives_%d.sk' % idx)
    surface_primitive_to_sketch.WriteSurfacePrimitivesToSolidSketch( \
      prim_file, prim_sketch_file, mesh_info['max_offsets'] + 10 * eps)
    sketch_harness_file_name = '%s_%d' % (output_dir.split('/')[-1], idx)
    sketch_harness_file = os.path.join(sketch_harness_dir, \
      sketch_harness_file_name) + '.sk'
    sketch_solver_file = os.path.join(sketch_harness_dir, \
      'csg_solver_%d.sk' % idx)
    # Sketch harness file.
    CreateSketch(sketch_harness_file, sketch_solver_file, \
      os.path.basename(sketch_data_file), sketch_idx_file, \
      os.path.basename(prim_sketch_file))
    # Run Sketch and get its log.
    sketch_output_file = os.path.join(sketch_output_dir, \
      sketch_harness_file_name + '.log')
    sketch_done = GetSketch(sketch_harness_file, sketch_output_file, \
      timeout)
    # Check if it succeeded.
    if not sketch_done or '[SKETCH] DONE' not in open(
            sketch_output_file).read():
        helper.PrintWithRedColor('Problem is too hard. Need segmentation.')
        return '', False
    helper.PrintWithGreenColor('Sketch succeeded.')
    # Display the solution.
    sketch_solution = GetSketchCompile(sketch_harness_file)
    # Save the results into a scad file.
    csg_file = os.path.join(csg_output_dir, 'csg_%d.scad' % idx)
    f = open(csg_file, 'w')
    f.write(sketch_solution)
    f.close()
    # As a sanity check.
    unsatisfied_pos, unsatisfied_neg = CheckPointConstraints(csg_file, \
      all_pos_constraints, all_neg_constraints)
    if unsatisfied_pos.size + unsatisfied_neg.size > 0:
        helper.PrintWithRedColor('Still see unsatisfied constraints. ' \
          'Should never happen.')
        sys.exit(-1)
    # Done.
    return sketch_solution, True
コード例 #12
0
def SetupSketchPipeline(args):
    global num_counter_samples
    global eps
    global num_init_samples
    global max_iter
    global mesh_file_loc
    global surface_density
    global seg_num
    global timeout
    global volume_density

    global output_dir
    global sketch_output_dir
    global point_output_dir
    global csg_output_dir
    global sketch_harness_dir

    build_dir = os.path.realpath(args.builddir)
    num_counter_samples = int(args.countersample)
    eps = float(args.eps)
    num_init_samples = int(args.initsample)
    max_iter = int(args.max_iter)
    mesh_file_loc = os.path.realpath(args.mesh)
    method = args.method
    output_dir = os.path.realpath(args.outdir)
    surface_density = float(args.surfacedensity)
    seg_num = int(args.seg)
    timeout = int(args.timeout)
    volume_density = float(args.volumedensity)

    # Check arguments.
    if not os.path.exists(build_dir):
        helper.PrintWithRedColor('Build dir does not exist.')
        sys.exit(-1)
    if num_counter_samples <= 0:
        print('Warning: countersample too small. Using 100 instead.')
        num_counter_samples = 100
    if eps < 1e-3:
        print('Warning: eps too small. Using 1e-3 instead.')
        eps = 1e-3
    if num_init_samples <= 0:
        print('Warning: initsample too small. Using 1000 instead.')
        num_init_samples = 1000
    if max_iter <= 0:
        print('Warning: invalid max iter. Use 10 instead.')
        max_iter = 10
    if not os.path.isfile(mesh_file_loc):
        helper.PrintWithRedColor('Mesh file does not exist.')
        sys.exit(-1)
    if method != 'sketch':
        helper.PrintWithRedColor('Method should be sketch.')
        sys.exit(-1)
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    if surface_density <= 0:
        print('Warning: invalid surface density. Use 10000 instead.')
        sample_density = 10000
    if seg_num <= 1:
        print('Warning: invalid seg num. Use 2 instead.')
        seg_num = 2
    if timeout <= 0:
        print('Warning: invalid timeout. Use 600 instead.')
        timeout = 600
    if volume_density <= 0:
        print('Warning: invalid volume density. Use 1000 instead.')
        volume_density = 1000
    helper.PrintWithGreenColor('All arguments seem reasonable.')

    # Set up folders.
    sketch_output_dir = os.path.join(output_dir, 'sketch_output')
    if not os.path.exists(sketch_output_dir):
        os.makedirs(sketch_output_dir)
    point_output_dir = os.path.join(output_dir, 'points')
    if not os.path.exists(point_output_dir):
        os.makedirs(point_output_dir)
    csg_output_dir = os.path.join(output_dir, 'csg')
    if not os.path.exists(csg_output_dir):
        os.makedirs(csg_output_dir)
    sketch_harness_dir = os.path.join(output_dir, 'sketches')
    if not os.path.exists(sketch_harness_dir):
        os.makedirs(sketch_harness_dir)
コード例 #13
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--build_dir', default='', help='build directory path.')
    parser.add_argument('-dp', '--deps', action='store_false', help='Disable apt-get & py3 dependencies.')
    parser.add_argument('-eg', '--eigen', action='store_false', help='Disable Eigen install.') 
    parser.add_argument('-cg', '--cgal', action='store_false', help='Disable CGAL install.')
    parser.add_argument('-c', '--cpp', action='store_false', help='Disable source cpp compilation.')
    parser.add_argument('-sk', '--sketch', action='store_false', help='Disable sketch installation.')
    args = parser.parse_args()
    print('Arguments:', args)

    # Usage: python3 install.py -d <build folder>
    if not args.build_dir:
      print('Usage: python3 install.py -d <build_folder>')
      sys.exit(-1)

    build_folder = os.path.realpath(args.build_dir)
    root_folder = HERE
    if not os.path.exists(build_folder):
      os.makedirs(build_folder)
    helper.PrintWithGreenColor('Build folder created :{}'.format(build_folder))
    
    # Add a new environment variable to save the location of the root folder.
    env_variables['CSG_ROOT'] = os.environ['CSG_ROOT'] = root_folder
    
    # Check all C++ dependencies.
    if args.deps:
      print('Attempt to install build-essential, autoconf, libtool, flex, bison, '
            'mecurial, zsh, and cmake. Asking for sudo privilege.')
      # This works for Ubuntu 17.04 and 16.04.
      exit_code = helper.Run('sudo apt-get install gcc-6 g++-6 -y', None)
      if exit_code != 0:
        # This works for Ubuntu 14.04.
        helper.Run('sudo apt-get update')
        helper.Run('sudo apt-get install build-essential ' \
          'software-properties-common -y')
        helper.Run('sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y')
        helper.Run('sudo apt-get update')
        helper.Run('sudo apt-get install gcc-snapshot -y')
        helper.Run('sudo apt-get update')
        helper.Run('sudo apt-get install gcc-6 g++-6 -y')
        helper.Run('sudo apt-get install autoconf libtool flex bison '
          'mercurial zsh cmake')
    
      # Install python dependencies.
      helper.Run('python3 -m pip install -U pip setuptools')
      helper.Run('python3 -m pip install --upgrade pip')
      helper.Run('python3 -m pip install numpy scipy matplotlib ipython '
                 'jupyter pandas sympy nose')
      helper.Run('python3 -m pip install -U scikit-learn')
    
    # Install CGAL.
    InstallCGAL(build_folder, args.eigen)
    
    # Install Eigen-3.3.4.
    InstallEigen(root_folder, args.cgal)
    
    # Compile cpp.
    if args.cpp:
      cpp_build_folder = os.path.join(build_folder, 'cpp')
      if not os.path.exists(cpp_build_folder):
        os.makedirs(cpp_build_folder)
      os.chdir(cpp_build_folder)
      os.environ['CC'] = '/usr/bin/gcc-6'
      os.environ['CXX'] = '/usr/bin/g++-6'
      helper.Run('cmake -DCGAL_DIR=%s %s' % (env_variables['CGAL_DIR'], \
                                             os.path.join(root_folder, 'cpp')))
      helper.Run('make')
      helper.PrintWithGreenColor('C++ program compiled successfully.')
      env_variables['CSG_CPP_EXE'] = os.path.join(cpp_build_folder,
                                                  'csg_cpp_command')
    
    # Install Sketch.
    # Try calling Sketch. If it is successful, we are done.
    if CheckSketch(build_folder):
      SaveCustomizedEnvironmentVariables(env_variables, os.path.join(
        build_folder, 'ENVIRONMENT'))
      helper.PrintWithGreenColor('Installation Done.')
      sys.exit(0)
    
    # If we are here, Sketch is not properly installed.
    # First, install Oracle JDK 8.
    print('Attempt to install Oracle JDK 8. Asking for sudo privilege.')
    InstallJava()
    
    # Next, install maven.
    InstallMaven()
    
    # Download sketch-backend.
    sketch_folder = os.path.join(build_folder, 'sketch')
    if not os.path.exists(sketch_folder):
      os.makedirs(sketch_folder)
    if args.sketch:
      # Sketch-backend.
      os.chdir(sketch_folder)
      helper.Run('hg clone https://bitbucket.org/gatoatigrado/sketch-backend')
      helper.Run('mv sketch-backend sketch-backend-default')
      # Use this version of sketch.
      helper.Run('hg clone -r 04b3403 sketch-backend-default sketch-backend')

    sketch_backend_folder = os.path.join(sketch_folder, 'sketch-backend')
    env_variables['CSG_SKETCH_BACKEND'] = sketch_backend_folder

    if args.sketch:
      os.chdir(sketch_backend_folder)
      helper.Run('bash autogen.sh')
      helper.Run('./configure')
      helper.Run('make -j2')
      # Interestingly, I need to manually do the following copy and paste work to
      # avoid an error in sketch-frontend.
      sketch_solver_folder = os.path.join(sketch_backend_folder, 'src/SketchSolver')
      shutil.copyfile(os.path.join(sketch_solver_folder, 'libcegis.a'), \
                      os.path.join(sketch_solver_folder, '.libs/libcegis.a'))
      shutil.copyfile(os.path.join(sketch_solver_folder, 'cegis'), \
                      os.path.join(sketch_solver_folder, '.libs/cegis'))
    
    # Download sketch-frontend.
    os.chdir(sketch_folder)
    if args.sketch:
      helper.Run('hg clone https://bitbucket.org/gatoatigrado/sketch-frontend')
      helper.Run('mv sketch-frontend sketch-frontend-default')
      # Use this version of sketch.
      helper.Run('hg clone -r 42c057c sketch-frontend-default sketch-frontend')
    sketch_frontend_folder = os.path.join(sketch_folder, 'sketch-frontend')
    env_variables['CSG_SKETCH_FRONTEND'] = sketch_frontend_folder
    os.chdir(sketch_frontend_folder)
    if args.sketch:
      helper.Run('make system-install DESTDIR=/usr/bin SUDOINSTALL=1')
    
    # Now check Sketch again.
    if not CheckSketch(build_folder):
      helper.PrintWithRedColor('Failed to install Sketch. Please fix.')
      sys.exit(-1)
    
    SaveCustomizedEnvironmentVariables(env_variables, os.path.join(
      build_folder, 'ENVIRONMENT'))
    helper.PrintWithGreenColor('Installation Done.')