def preprocess_cfr(ceilings_org, walls_org, obj):
    '''
    Z is up, Y is thickness
    A ceiling is good:
      (1) not contains multiple rooms:
        cover no other ceilings
      (2) >= 3 edge walls
    A edge wall of a ceiling:
      In three points of the wall cenline: two corners and centroid
      at least two are on an edge of ceiling
  '''
    assert ceilings_org.ndim == walls_org.ndim == 2
    dis_threshold = 0.07
    if ceilings_org.shape[0] == 0:
        return ceilings_org
    if walls_org.shape[0] == 0:
        return np.zeros(shape=[0, 7], dtype=np.float32)

    #Bbox3D.draw_bboxes(walls_org, 'Z', False)
    #Bbox3D.draw_bboxes(ceilings_org, 'Z', False)
    ceilings = ceilings_org.copy()
    ceilings, keep_ids0 = clean_repeat(ceilings)
    walls = walls_org.copy()
    cn = ceilings.shape[0]

    ceilings[:, 2] = 0
    walls[:, 2] = 0
    walls[:, 5] = 0

    ceil_corners0 = Bbox3D.bboxes_corners(ceilings, 'Z')
    ceil_corners = np.take(ceil_corners0, Bbox3D._zpos_vs, axis=1)
    ceil_corners[:, :, 2] = 0

    ceiling_cens = ceilings[:, 0:3]
    wall_cenlines = Bbox3D.bboxes_centroid_lines(walls, 'X', 'Z')

    good_ceiling_ids0 = []
    bad_small_ids = []

    for c in range(cn):
        # (1)
        #print(f'c:{c}')
        ceil_c = ceilings[c:c + 1].copy()
        ceil_c[:, 3:6] += 0.2
        mask_overlap = Bbox3D.points_in_bbox(ceil_corners.reshape([-1, 3]),
                                             ceil_c).reshape([cn, 4])
        mask_overlap = mask_overlap.all(1)
        num_overlap = mask_overlap.sum() - 1
        ol_ids = np.where(mask_overlap)[0]
        ol_ids = [i for i in ol_ids if i != c]
        #if any_overlap:
        #  area_ol = np.product(tmp[ol_ids,3:5], axis=1).sum()
        #  area_c = np.product(ceilings[c,3:5])
        #  area_ol_rate = area_ol / area_c
        #  import pdb; pdb.set_trace()  # XXX BREAKPOINT
        #  pass
        if Debug and 0:
            print(f'ceiling, contain {num_overlap} other celings')
            box_show = np.concatenate([walls_org, ceilings_org[c:c + 1]], 0)
            Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)
        if num_overlap > 1:
            continue
        #if num_overlap >0:
        #  bad_small_ids += ol_ids

        # (2)
        edge_wall_num, winc_state = is_edge_wall_of_ceiling(
            wall_cenlines, ceilings[c], walls_org)
        if edge_wall_num >= 3 or (edge_wall_num == 2 and
                                  (winc_state == 3).all()):
            good_ceiling_ids0.append(c)

    #good_ceiling_ids1 = [i for i in good_ceiling_ids0 if i not in bad_small_ids]
    good_ceiling_ids1 = keep_ids0[good_ceiling_ids0]
    good_ceiling_ids1 = np.array(good_ceiling_ids1).astype(np.int)
    rm_num = cn - good_ceiling_ids1.shape[0]

    bad_ceiling_ids = np.array(
        [i for i in range(cn) if i not in good_ceiling_ids1]).astype(np.int32)
    new_ceilings = ceilings_org[good_ceiling_ids1]

    if Debug and rm_num > 0:
        print(f'{cn} -> {good_ceiling_ids1.shape[0]}')
        box_show = np.concatenate([walls_org, ceilings_org[good_ceiling_ids1]],
                                  0)
        Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)
        if rm_num > 0:
            box_show = np.concatenate(
                [walls_org, ceilings_org[bad_ceiling_ids]], 0)
            Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)
        import pdb
        pdb.set_trace()  # XXX BREAKPOINT
        #show_walls_1by1(new_ceilings)
        pass
    return new_ceilings
Beispiel #2
0
def preprocess_doors(doors0, walls, door_thickness=0.18):
    '''
  doors0:[d,7]
  walls:[w,7]
  '''
    door_n = doors0.shape[0]
    if door_n == 0:
        return doors0
    wall_n = walls.shape[0]
    walls_1 = walls.copy()
    # (1) Find the coresponding wall of each door
    # (1.1) Get the four top lines of each door
    door_corners = Bbox3D.bboxes_corners(doors0, 'Z')[:, 0:4, :]  # [d,4,3]
    door_lines0 = np.take(door_corners, Bbox3D._lines_z0_vids,
                          axis=1)  # [d,4,2,3]
    door_lines1 = door_lines0.reshape(-1, 2, 3)
    # (1.2) Get the centroid lines of each wall
    wall_cen_lines = Bbox3D.bboxes_centroid_lines(walls_1, 'X', 'Z')

    # (1.3) Get the intersections_2d between lines and walls
    # A door matches a wall means: there are two top lines of the door, which are
    # intersected with the wall centroid line.
    dw_ints = lines_intersection_2d(door_lines1[:, :, 0:2],
                                    wall_cen_lines[:, :, 0:2], True, True)
    dw_ints = dw_ints.reshape(door_n, 4, wall_n, 2)  # [d,4,w,2]
    tmp0 = (1 - np.isnan(dw_ints)).sum(3)  # [d,4,w]
    door_mask0 = tmp0.sum(1) == 4
    door_matched0 = door_mask0.sum(1).reshape(-1, 1)

    # (1.4) Sometimes on door can match two walls. Remove the confused one by:
    # The right wall should not contain any corners
    dc_in_wall_mask = Bbox3D.points_in_bbox(door_corners.reshape(-1, 3),
                                            walls).reshape(door_n, 4, wall_n)
    dc_in_wall_mask = np.any(dc_in_wall_mask, axis=1)
    bad_match = (door_matched0 > 1) * dc_in_wall_mask
    door_mask = door_mask0 * (1 - bad_match)

    door_ids, wall_ids = np.where(door_mask)
    success_num = door_ids.shape[0]

    # (2) Pick the failed door ids
    wall_num_each_door = door_mask.sum(1)
    fail_match_door_ids = np.where(wall_num_each_door != 1)[0]

    walls_good = walls[wall_ids]
    yaws = limit_period(walls_good[:, -1], 0, np.pi / 2)

    intersections_2d = []
    for i in range(success_num):
        door_idx = door_ids[i]
        cids = np.where(tmp0[door_idx, :, wall_ids[i]])[0]
        ints_i = dw_ints[door_idx, cids, wall_ids[i]]
        intersections_2d.append(ints_i.reshape(1, 2, 2))
    if len(intersections_2d) == 0:
        return np.empty([0, 7])
    intersections_2d = np.concatenate(intersections_2d, 0)

    doors_centroids_2d = np.mean(intersections_2d, 1)
    doors_length = np.linalg.norm(intersections_2d[:, 0] -
                                  intersections_2d[:, 1],
                                  axis=1)
    doors_length -= door_thickness * np.sin(yaws * 2)

    doors_new = doors0[door_ids].copy()
    doors_new[:, 0:2] = doors_centroids_2d
    doors_new[:, 3] = doors_length
    doors_new[:, 4] = door_thickness
    doors_new[:, 6] = walls_good[:, -1]

    if DEBUG and fail_match_door_ids.shape[0] > 0:
        print(f"fail_match_door_ids:{fail_match_door_ids}")
        show_all([doors0[fail_match_door_ids], walls])
        #for dids in fail_d_ids:
        #  fail_w_ids = np.where(door_mask[dids])[0]
        #  show_all([doors0[dids].reshape(-1,7), walls[fail_w_ids].reshape(-1,7)])
        import pdb
        pdb.set_trace()  # XXX BREAKPOINT
        pass

    if DEBUG:
        show_all([doors0, doors_new, walls])
    return doors_new
Beispiel #3
0
def merge_2pieces_of_1wall(bbox0, bbox1, dim):
    '''
    [1,7] [1,7]
    two box can merge, when:
    z, size_y, size_z same
    yaw0 = yaw1 = angle of c0_c1
    out: [1,7]
  '''
    from utils3d.geometric_util import angle_with_x
    assert dim == 'X' or 'Y'
    dim = 0 if dim == 'X' else 1

    bbox0 = bbox0.reshape([1, 7])
    bbox1 = bbox1.reshape([1, 7])
    dif = bbox1 - bbox0
    dif[0, -1] = limit_period(dif[0, -1], 0.5, np.pi)

    z_same = np.abs(dif[0, 2]) < 0.01
    if dim == 0:
        # o means the other here, if dim=='X', o='Y'
        so_same = np.abs(dif[0, 3 + 1 - dim]) < 0.05
    else:
        so_same = np.abs(dif[0, 3 + 1 - dim]) < 0.15
    sz_same = np.abs(dif[0, 3 + 2]) < 0.01
    z_sames0 = z_same and sz_same
    if z_sames0:
        z_sames = z_sames0
    else:
        z0_max = bbox0[0, 2] + bbox0[0, 5] * 0.5
        z0_min = bbox0[0, 2] - bbox0[0, 5] * 0.5
        z1_max = bbox1[0, 2] + bbox1[0, 5] * 0.5
        z1_min = bbox1[0, 2] - bbox1[0, 5] * 0.5
        zmin_dif = np.abs(z1_min - z0_min)
        zmax_dif = np.abs(z1_max - z0_max)
        zmin_same = zmin_dif < 0.01
        zmax_same = zmax_dif < 0.03
        z_sames = zmin_same and zmax_same

        if not zmax_same:
            iou_xy = rotate_iou_gpu(bbox0[:, [0, 1, 3, 4, 6]],
                                    bbox1[:, [0, 1, 3, 4, 6]])
            #print(f'box0 : {bbox0}')
            #print(f'box1 : {bbox1}')
            print(
                f'zmin_dif:{zmin_dif}, zmax_dif:{zmax_dif}\n iou_xy:{iou_xy}\n'
            )
            if iou_xy > MERGE_Z_ANYWAY_XYIOU_THRESHOLD:
                print('Merge even z is different')
                z_sames = True
            else:
                print('abort merging because of z is different')
            if DEBUG and False:
                box_show = np.concatenate([bbox0, bbox1], 0)
                Bbox3D.draw_bboxes(box_show, 'Z', False)
                import pdb
                pdb.set_trace()  # XXX BREAKPOINT
                pass

        if z_sames:
            zmin_new = min(z0_min, z1_min)
            zmax_new = max(z0_max, z1_max)
            z_new = (zmin_new + zmax_new) / 2.0
            z_size_new = zmax_new - zmin_new

            bbox0[0, 2] = z_new
            bbox0[0, 5] = z_size_new
            bbox1[0, 2] = z_new
            bbox1[0, 5] = z_size_new

    yaw_same = np.abs(dif[0, -1]) < 0.05

    if not (z_sames and so_same and yaw_same):
        return None

    cen_direc = dif[:, 0:2]
    if dim == 0:
        cen_line0 = Bbox3D.bboxes_centroid_lines(bbox0, 'X', 'Z')
        dis_01 = vertical_dis_1point_lines(bbox1[0, 0:3], cen_line0)[0]
        overlap_mask0 = dis_01 < bbox0[0, 4] * 0.51 + 0.01
        if not overlap_mask0:
            return None

        cen_dis = np.linalg.norm(dif[0, 0:3])
        overlap_mask1 = cen_dis < (bbox0[0, 3] + bbox1[0, 3]) * 0.5 + 0.01
        if not overlap_mask1:
            return None

    centroid_lines1 = Bbox3D.bboxes_centroid_lines(bbox1,
                                                   'X' if dim == 1 else 'Y',
                                                   'Z')
    cen_dis = vertical_dis_1point_lines(bbox0[0, 0:3], centroid_lines1)[0]

    size_dim0 = bbox0[0, 3 + dim]
    size_dim1 = bbox1[0, 3 + dim]

    is_box0_covered_by_1 = size_dim1 * 0.5 > cen_dis + size_dim0 * 0.5
    is_box1_covered_by_0 = size_dim0 * 0.5 > cen_dis + size_dim1 * 0.5

    if is_box0_covered_by_1:
        merged = bbox1
    elif is_box1_covered_by_0:
        merged = bbox0
    else:
        k = size_dim1 / (size_dim0 + size_dim1)
        new_centroid = bbox0[0, 0:3] + (bbox1[0, 0:3] - bbox0[0, 0:3]) * k
        new_size_dim = (size_dim0 + size_dim1) / 2 + cen_dis

        merged = (bbox0 + bbox1) / 2
        merged[:, -1] = ave_angles(bbox0[:, -1], bbox1[:, -1], scope_id=1)
        if np.abs(bbox1[0, -1] - bbox0[0, -1]) > np.pi * 0.5:
            merged[0, -1] = (np.abs(bbox0[0, -1]) + np.abs(bbox1[0, -1])) / 2.0
        merged[0, 0:3] = new_centroid
        merged[0, 3 + dim] = new_size_dim

    #
    show = False
    if show:
        box_show = np.concatenate([bbox0, bbox1, merged], 0)
        box_show[2, 2] += 0.1
        Bbox3D.draw_bboxes(box_show, 'Z', False)
        import pdb
        pdb.set_trace()  # XXX BREAKPOINT
        pass
    return merged
Beispiel #4
0
def find_close_walls(walls):
    '''
    walls: [n,7]
  '''
    show = False
    if show:
        walls0 = walls.copy()

    corners = Bbox3D.bboxes_corners(walls, 'Z')  # [n,8,3]
    cen_lines_x = Bbox3D.bboxes_centroid_lines(walls, 'X', 'Z')  # [n,2,3]
    cen_lines_y = Bbox3D.bboxes_centroid_lines(walls, 'Y', 'Z')  # [n,2,3]
    n = walls.shape[0]

    dis_x0 = vertical_dis_points_lines(
        corners.reshape([-1, 3])[:, 0:2], cen_lines_x[:, :,
                                                      0:2]).reshape([n, 8, n])
    dis_x_ave = dis_x0.mean(1)  # [n,n]
    dis_x_max = dis_x0.max(1)  # [n,n]
    inside_x_ave = dis_x_ave / (walls[:, 4].reshape([1, n]) * 0.501 + 0.01)
    inside_x_max = dis_x_max / (walls[:, 4].reshape([1, n]) * 0.8 + 0.03)
    inside_x_mask = (inside_x_ave < 1) * (inside_x_max < 1)

    dis_y0 = vertical_dis_points_lines(
        corners.reshape([-1, 3])[:, 0:2], cen_lines_y[:, :,
                                                      0:2]).reshape([n, 8, n])
    dis_y_ave = dis_y0.max(1)  # [n,n]
    dis_y_max = dis_y0.max(1)  # [n,n]
    inside_y_ave = dis_y_ave / (walls[:, 3].reshape([1, n]) * 0.515 + 0.03)
    inside_y_max = dis_y_max / (walls[:, 3].reshape([1, n]) * 0.55 + 0.05)
    inside_y_mask = (inside_y_ave < 1) * (inside_y_max < 1)

    inside_mask = inside_x_mask * inside_y_mask
    # inside_mask[i,j] is True means walls[i] is inside of walls[j]

    #print(inside_x)
    #print(inside_y)
    #print(inside_mask)

    remain_mask = np.array([True] * n)
    for i in range(n - 1):
        for j in range(i + 1, n):
            if inside_mask[i, j] or inside_mask[j, i]:
                if inside_mask[i, j] and inside_mask[j, i]:
                    # (A) If inside with each other, merge two close walls
                    walls[j] = merge_2close_walls(walls[i], walls[j])
                    remain_mask[i] = False
                elif inside_mask[i, j]:
                    # (B) If one is inside another, remove the inside one
                    remain_mask[i] = False
                elif inside_mask[j, i]:
                    remain_mask[j] = False
    walls_new = walls[remain_mask]
    rm_n = np.sum(remain_mask)
    print(f'clean close walls {n} -> {rm_n}')

    if show:
        show_boxes = walls0
        show_boxes[:, 2] -= 0.2
        show_boxes = np.concatenate([show_boxes, walls_new], 0)
        Bbox3D.draw_bboxes(show_boxes, 'Z', False)
        import pdb
        pdb.set_trace()  # XXX BREAKPOINT
        #show_walls_offsetz(walls_new)
        #show_walls_1by1(walls_new)

    return walls_new
Beispiel #5
0
def merge_pieces_of_same_walls_alongY(wall_bboxes):
    '''
    1) Find all the walls which are A) parallel along X, B) one of cen_corners is very close
      C) centroid of one wall is inside of another
    2) Merge along Y
  '''
    from utils3d.geometric_util import angle_with_x, vertical_dis_points_lines
    if wall_bboxes.shape[0] == 0:
        return wall_bboxes
    show = False
    if show:
        wall_bboxes0 = wall_bboxes.copy()
        wall_bboxes0[:, 2] -= 1

    n = wall_bboxes.shape[0]
    cen_lines = Bbox3D.bboxes_centroid_lines(wall_bboxes,
                                             cen_axis='X',
                                             up_axis='Z')  # [n,2,3]
    cen_direc = cen_lines[:, 1, :] - cen_lines[:, 0, :]  # [n,3]
    np.linalg.norm(cen_direc[:, 0:2], axis=1)
    angles = angle_with_x(cen_direc[:, 0:2], 1)
    boxes_merged_extra = []
    remain_mask = np.array([True] * n)
    merge_y_num = 0
    split_and_merge_num = 0

    for i in range(n - 1):
        # 1) parallel along X
        angles_dif = angles[i] - angles[i + 1:]
        # make to [0,np.pi/2]
        angles_dif = np.abs(limit_period(angles_dif, 0.5, np.pi))
        angle_mask = angles_dif < 7 * np.pi / 180

        # 2) one of centroid line corners is very close
        cen_dis = cen_lines[i:i + 1].reshape(
            [1, 2, 1, 3]) - cen_lines[i + 1:].reshape([-1, 1, 2, 3])
        cen_dis = np.linalg.norm(cen_dis, axis=3)
        cen_dis_min = cen_dis.min(axis=1).min(axis=1)
        cen_dis_max = cen_dis.max(axis=1).max(axis=1)
        thickness_sum = wall_bboxes[:, 4] * 0.5 + wall_bboxes[i, 4] * 0.5
        thickness_sum = thickness_sum[i + 1:]
        cendis_mask = cen_dis_min < thickness_sum

        # 3) the other centroid line corner is inside of the long box
        centroid_dis = np.linalg.norm(wall_bboxes[i:i + 1, 0:3] -
                                      wall_bboxes[i + 1:, 0:3],
                                      axis=1)
        #tmp = np.maximum(wall_bboxes[i,3], wall_bboxes[i+1:,3])
        tmp = (wall_bboxes[i, 3] + wall_bboxes[i + 1:, 3]) * 0.45 - 0.1
        centroid_mask = centroid_dis < tmp

        #if i==4:
        #  import pdb; pdb.set_trace()  # XXX BREAKPOINT
        #  show_boxes = wall_bboxes[[4,12]]
        #  Bbox3D.draw_bboxes(show_boxes, 'Z', False)
        #  pass

        mask_i = angle_mask * cendis_mask * centroid_mask
        if mask_i.any():
            ids = np.where(mask_i)[0] + i + 1
            # 5) the centroid corner used to split the other

            # 4) vertical dis
            vertical_dis = vertical_dis_points_lines(cen_lines[i],
                                                     cen_lines[ids]).mean(0)
            ave_thickness = (wall_bboxes[i, 4] + wall_bboxes[ids, 4]) * 0.5
            thickness_gap_rate = vertical_dis / ave_thickness
            verdis_mask = (thickness_gap_rate > 0.2) * (thickness_gap_rate <
                                                        1.2)

            ids = ids[verdis_mask]
            vertical_dis = vertical_dis[verdis_mask]

            is_need_merge = ids.shape[0] > 0

            if is_need_merge:
                # split the longer box, and merge the shorter one along Y
                k = ids.shape[0]
                for j in range(k):
                    idx = ids[j]

                    size_x_i = wall_bboxes[i, 3]
                    size_x_j = wall_bboxes[idx, 3]
                    size_x_rate = size_x_i / size_x_j
                    print(f'size_x_rate: {size_x_rate}')
                    if np.abs(size_x_rate - 1) < 0.15:
                        merge_y_num += 1
                        box_merge = merge_2pieces_of_1wall(
                            wall_bboxes[i], wall_bboxes[idx], 'Y')

                        if show and False:
                            show_boxes = np.concatenate([
                                wall_bboxes[i:i + 1], wall_bboxes[idx:idx + 1]
                            ], 0)
                            if box_merge is not None:
                                show_boxes = np.concatenate(
                                    [show_boxes, box_merge], 0)
                                show_boxes[-1, 2] += 0.2
                            else:
                                import pdb
                                pdb.set_trace()  # XXX BREAKPOINT
                                pass
                            show_boxes = np.concatenate(
                                [show_boxes, wall_bboxes0], 0)
                            Bbox3D.draw_bboxes(show_boxes, 'Z', False)
                            pass
                        if box_merge is not None:
                            wall_bboxes[idx] = box_merge.reshape([7])
                            remain_mask[i] = False
                        else:
                            print(
                                'The two walls cannot be merged along Y, this should not happen normally'
                            )
                            print(
                                'merge_pieces_of_same_walls_alongY again after crop_walls to solve some special case: Originally, a wall is broken by no intersection like 0058113bdc8bee5f387bb5ad316d7b28'
                            )
                            #show_boxes = np.concatenate([wall_bboxes[i:i+1], wall_bboxes[idx:idx+1]], 0)
                            #Bbox3D.draw_bboxes(wall_bboxes, 'Z', False, highlight_ids=[idx, i])
                            #Bbox3D.draw_bboxes(show_boxes, 'Z', False)
                            #import pdb; pdb.set_trace()  # XXX BREAKPOINT
                            #pass
                            #raise NotImplementedError

                    else:
                        # the longer box need to be split along X before merging
                        split_and_merge_num += 1
                        cen_dis_ij = cen_dis[idx - i - 1]
                        if size_x_rate > 1:
                            longer_idx = i
                            short_idx = idx
                            cen_dis_ij = cen_dis_ij.min(axis=0)
                        else:
                            longer_idx = idx
                            short_idx = i
                            cen_dis_ij = cen_dis_ij.min(axis=1)
                        # find the intersection point on longer box
                        far_corner_id = int(cen_dis_ij[0] < cen_dis_ij[1])
                        cen_dir_longer = cen_lines[longer_idx,
                                                   1] - cen_lines[longer_idx,
                                                                  0]
                        cen_dir_longer /= np.linalg.norm(cen_dir_longer)
                        sl_dir = cen_lines[
                            short_idx, far_corner_id] - cen_lines[longer_idx,
                                                                  0]
                        intersection = np.sum(
                            sl_dir * cen_dir_longer
                        ) * cen_dir_longer + cen_lines[longer_idx, 0]
                        # offset: half of the thickness
                        intersection += cen_dir_longer * wall_bboxes[i,
                                                                     4] * 0.5

                        splited_boxes = Bbox3D.split_wall_by_centroid_intersections(
                            wall_bboxes[longer_idx],
                            intersection.reshape([1, 3]))  # [2,7]

                        if splited_boxes.shape[0] == 1:
                            print(
                                '\n\n\t\tComplicated situation, not solved well yet.\n\n'
                            )
                            box_merge = None
                            if False and DEBUG and splited_boxes.shape[0] == 1:
                                box_tmp = np.array(
                                    [[0, 0, 0, 0.5, 0.5, 0.5, 0]])
                                box_tmp[0, 0:3] = intersection.reshape([1, 3])
                                boxes_show = np.concatenate([
                                    box_tmp, wall_bboxes[longer_idx].reshape(
                                        [-1, 7])
                                ], 0)
                                Bbox3D.draw_points_bboxes(
                                    intersection.reshape([1, 3]), boxes_show,
                                    'Z', False)
                        else:
                            tmp = wall_bboxes[short_idx,
                                              0:3] - splited_boxes[:, 0:
                                                                   3]  # [2,3]
                            tmp = np.linalg.norm(tmp, axis=1)  # [2]
                            merge_id = int(tmp[0] > tmp[1])
                            box_merge = merge_2pieces_of_1wall(
                                wall_bboxes[short_idx],
                                splited_boxes[merge_id], 'Y')

                        if show and False:
                            #if box_merge is None:
                            show_boxes = np.concatenate([
                                wall_bboxes[i:i + 1], wall_bboxes[idx:idx + 1]
                            ], 0)
                            Bbox3D.draw_points_bboxes(
                                intersection.reshape([1, 3]), show_boxes, 'Z',
                                False)
                            show_boxes = np.concatenate(
                                [show_boxes, splited_boxes], 0)
                            show_boxes[-1, 2] += 0.5
                            show_boxes[-2, 2] += 0.7
                            if box_merge is not None:
                                show_boxes = np.concatenate(
                                    [show_boxes, box_merge], 0)
                                show_boxes[-1, 2] += 1
                            show_boxes = np.concatenate(
                                [show_boxes, wall_bboxes0], 0)
                            Bbox3D.draw_bboxes(show_boxes, 'Z', False)
                            import pdb
                            pdb.set_trace()  # XXX BREAKPOINT
                            pass

                        if box_merge is None:
                            # temperally solution, may because of a wall being changed several
                            # times
                            remain_mask[short_idx] = False
                        else:
                            wall_bboxes[longer_idx] = splited_boxes[1 -
                                                                    merge_id]
                            wall_bboxes[short_idx] = box_merge.reshape([7])
                            boxes_merged_extra.append(box_merge.reshape([1,
                                                                         7]))

    wall_bboxes_new = wall_bboxes[remain_mask]
    #boxes_merged_extra = np.concatenate(boxes_merged_extra, 0)
    #wall_bboxes_new = np.concatenate([wall_bboxes, boxes_merged_extra], 0)
    print(
        f'merge_y_num:{merge_y_num}  split_and_merge_num:{split_and_merge_num}'
    )
    if show:
        show_walls_offsetz(wall_bboxes_new)
        #show_walls_offsetz(wall_bboxes)
        #show_walls_offsetz(wall_bboxes0[remain_mask])
        show_walls_offsetz(wall_bboxes0[np.logical_not(remain_mask)])
        #show_walls_offsetz(boxes_merged_extra)
    return wall_bboxes_new
def preprocess_cfr(ceilings_org, walls_org, obj):
    '''
  Z is up, Y is thickness
  '''
    #Bbox3D.draw_bboxes(walls, 'Z', False)
    ceilings = ceilings_org.copy()
    walls = walls_org.copy()
    walls = replace_slant_walls(walls)

    dis_threshold = 0.07

    ceiling_cens = ceilings[:, 0:3]
    ceiling_cens[:, 2] = 0
    ceil_cenlines_x = Bbox3D.bboxes_centroid_lines(ceilings, 'X', 'Z')
    ceil_cenlines_x[:, :, 2] = 0
    #ceil_cenlines_y = Bbox3D.bboxes_centroid_lines(ceilings, 'Y', 'Z')
    wall_cenlines = Bbox3D.bboxes_centroid_lines(walls, 'X', 'Z')
    wall_cenlines[:, :, 2] = 0

    ceilings_shrink = ceilings.copy()
    ceilings_shrink[:, 3:5] -= 0.3

    cn = ceilings.shape[0]

    ## Find edge wall nums
    good_ceiling_ids = []
    for c in range(cn):
        # (0.1) If no any other overlap ceiling, try to keep it
        # Otherwise, delete it when  >3 wall inside ceiling
        tmp = np.delete(ceiling_cens.copy(), c, axis=0)
        any_overlap = Bbox3D.points_in_bbox(tmp, ceilings[c:c + 1]).any()
        if any_overlap:
            wall_corner0_in_ceil = Bbox3D.points_in_bbox(
                wall_cenlines[:, 0, :], ceilings_shrink[c:c + 1])
            wall_corner1_in_ceil = Bbox3D.points_in_bbox(
                wall_cenlines[:, 1, :], ceilings_shrink[c:c + 1])
            wall_inside_ceil = wall_corner0_in_ceil + wall_corner1_in_ceil
            wall_inside_ceil_ids = np.where(wall_inside_ceil)[0]
            nwic = wall_inside_ceil_ids.shape[0]

            if nwic > 3:
                if Debug and 1:
                    print(f'bad ceiling, contain {nwic} walls inside')
                    box_show = np.concatenate(
                        [walls_org, ceilings_org[c:c + 1]], 0)
                    Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)

                    box_show = np.concatenate([
                        walls_org[wall_inside_ceil_ids], ceilings_org[c:c + 1]
                    ], 0)
                    Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)
                import pdb
                pdb.set_trace()  # XXX BREAKPOINT
                continue

        # (1) the central corners of wall are inside of ceiling
        wall_cenlines_auged = line_aug(wall_cenlines)
        cw_cen_dis = ceiling_cens[c].reshape([1, 1, -1]) - wall_cenlines_auged
        cw_cen_dis = np.linalg.norm(cw_cen_dis, axis=2)
        ceil_diag_size = np.linalg.norm(ceilings[c, 3:5])
        on_inside_ceil = (cw_cen_dis - ceil_diag_size / 2 <
                          dis_threshold).sum(1) >= 2

        if Debug and 0:
            #Bbox3D.draw_points_bboxes(wall_cenlines_auged.reshape([-1,3]), walls, 'Z', False)
            inside_ids = np.where(on_inside_ceil)[0]
            box_show = np.concatenate(
                [walls_org[inside_ids], ceilings_org[c:c + 1]], 0)
            Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)

        # (2) along x: wall central line is on x boundaries of ceiling
        dis_cw = vertical_dis_points_lines(ceil_cenlines_x[c], wall_cenlines)
        ceil_y_thickness = ceilings[c, 4]
        mask_x0 = np.abs(dis_cw[0] - dis_cw[1]) < dis_threshold
        mask_x1 = (np.abs(dis_cw - ceil_y_thickness / 2) <
                   dis_threshold).all(0)
        mask_x = mask_x0 * mask_x1 * on_inside_ceil
        wall_on_ceil_boundary_parall_x = np.where(mask_x)[0]
        num_edgew_x = clean_edge_wall_same_side(
            wall_cenlines[wall_on_ceil_boundary_parall_x])

        # (3) along x: wall central line is on x boundaries of ceiling
        ceil_x_thickness = ceilings[c, 3]
        mask_y0 = dis_cw < dis_threshold
        mask_y1 = np.abs(dis_cw - ceil_x_thickness) < dis_threshold
        mask_y = (mask_y0 + mask_y1).all(0)
        mask_y = mask_y * on_inside_ceil
        wall_on_ceil_boundary_parall_y = np.where(mask_y)[0]
        num_edgew_y = clean_edge_wall_same_side(
            wall_cenlines[wall_on_ceil_boundary_parall_y])

        #Bbox3D.point_in_box(wall_cenlines, ceilings[])

        edge_wall_num = num_edgew_x + num_edgew_y

        if edge_wall_num >= 3:
            good_ceiling_ids.append(c)

        if Debug and edge_wall_num < 3 and 0:
            print(f'edge_wall_num: {edge_wall_num}')
            box_show = np.concatenate([walls_org, ceilings_org[c:c + 1]], 0)
            Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)
            #Bbox3D.draw_points_bboxes(ceil_cenlines_x[c], box_show, 'Z', False)
            #Bbox3D.draw_points_bboxes(ceil_cenlines_x[c], ceilings[c:c+1], 'Z', False)

            edge_walls_x = walls_org[wall_on_ceil_boundary_parall_x]
            box_x = np.concatenate([edge_walls_x, ceilings_org[c:c + 1]], 0)
            #Bbox3D.draw_bboxes_mesh(box_x, 'Z', False)

            edge_walls_y = walls_org[wall_on_ceil_boundary_parall_y]
            box_y = np.concatenate([edge_walls_y, ceilings_org[c:c + 1]], 0)
            #Bbox3D.draw_bboxes_mesh(box_y, 'Z', False)

            walls_inside = walls_org[wall_inside_ceil_ids]
            box_ins = np.concatenate([walls_inside, ceilings_org[c:c + 1]], 0)
            #Bbox3D.draw_bboxes_mesh(box_ins, 'Z', False)

            import pdb
            pdb.set_trace()  # XXX BREAKPOINT
            pass

    good_ceiling_ids = np.array(good_ceiling_ids).reshape([-1])
    new_cn = good_ceiling_ids.shape[0]
    print(f'\n\n{obj} {cn} -> {new_cn}')
    if new_cn == 0:
        new_ceilings = ceilings_org[0:0]
    else:
        new_ceilings = ceilings_org[good_ceiling_ids]
    if Debug and new_cn < cn:
        print(good_ceiling_ids)
        box_show = np.concatenate([walls_org, new_ceilings], 0)
        Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)

        bad_ceil_ids = np.array([
            i for i in range(cn) if i not in good_ceiling_ids
        ]).astype(np.int32)
        if bad_ceil_ids.shape[0] > 0:
            box_show = np.concatenate([walls_org, ceilings_org[bad_ceil_ids]],
                                      0)
            Bbox3D.draw_bboxes_mesh(box_show, 'Z', False)
        import pdb
        pdb.set_trace()  # XXX BREAKPOINT
    return ceilings