def clean_edge_wall_same_side(cenlines):
    '''
  [n,2,3]
  '''
    n = cenlines.shape[0]
    if n <= 1:
        return n
    rm_ids = []
    for i in range(n - 1):
        centroid_i = cenlines[i].mean(0).reshape([1, 3])
        dis = vertical_dis_points_lines(centroid_i, cenlines[i + 1:])
        if dis.min() < 0.05:
            rm_ids.append(i)
    return n - len(rm_ids)
Esempio n. 2
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
Esempio n. 3
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
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