UNPKG

iobroker.roborock

Version:
1,548 lines (1,340 loc) 87.5 kB
import { Point as IPoint } from "../MapHelper"; export const CONSTANTS = { BLACK: -128, WHITE: 127, BOUNDARY: -2, }; export interface Rect { x: number; y: number; width: number; height: number; } export interface ChainPoint { chain_point: Point; } export interface DoorInfo { door_point: Point[]; area_id: number[]; } export interface RoomInfo { tid: number; center_pose: Point; chain_infor: ChainPoint[]; door_info: DoorInfo[]; } export interface TMapStruct { map: Int8Array | Uint8Array; x_min: number; x_max: number; y_min: number; y_max: number; resolution: number; info: RoomInfo[] | null; } export class Point implements IPoint { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } } export function beautify(tMapStruct: TMapStruct): { result: Int8Array | Uint8Array } { let map = tMapStruct.map; let tRect: Rect = { x: 0, y: 0, width: 0, height: 0 }; const x_min = tMapStruct.resolution * Math.round(tMapStruct.x_min / tMapStruct.resolution); const y_min = tMapStruct.resolution * Math.round(tMapStruct.y_min / tMapStruct.resolution); const resolution = tMapStruct.resolution; const size_x = parseInt(Math.round((tMapStruct.x_max - tMapStruct.x_min) / tMapStruct.resolution).toString()); const size_y = parseInt(Math.round((tMapStruct.y_max - tMapStruct.y_min) / tMapStruct.resolution).toString()); let black_boundary: any[] = []; let non_boundary_noise: any[] = []; let all_region: any[] = []; const m_four_Dir = [[0, -1], [-1, 0], [1, 0], [0, 1]]; const m_eight_Dir = [[1, 0], [-1, 0], [0, 1], [0, -1], [-1, -1], [1, -1], [-1, 1], [1, 1]]; const findRoiMap_result = findRoiMap(tRect, map, size_x, size_y); tRect = findRoiMap_result.result; const expandBlackRect_result = expandBlackRect(4, 4, map[0], tRect, map, size_x, size_y); map = expandBlackRect_result.result; const expandWhiteRect_result = expandWhiteRect(4, 4, map[0], tRect, map, size_x, size_y); map = expandWhiteRect_result.result; const refineBoundary_reult1 = refineBoundary(0, 10, tRect, map, size_x); map = refineBoundary_reult1.result; const result = eliminateNonBoundaryNoise(non_boundary_noise, tRect, CONSTANTS.WHITE, CONSTANTS.BLACK, 0, map, size_x); non_boundary_noise = result.tempnonBoundaryNoise; map = result.map; const expandSingleConvexBoundary_result = expandSingleConvexBoundary(50, CONSTANTS.BLACK, 4, 4, tRect, map, size_x); map = expandSingleConvexBoundary_result.result; if (typeof global !== "undefined") (global as any).mapSnapshotOrig = new Int8Array(map); const all_region_result = findWhiteConnectComponent(all_region, 150, tRect, size_x, map); all_region = all_region_result.result; const result1 = removeIndependentRegion(all_region, black_boundary, 2, tRect, map, size_x); black_boundary = result1.temp_black_boundary; map = result1.map; const result2 = fillNonBoundaryNoise2(non_boundary_noise, tRect, map, size_x); non_boundary_noise = result2.nonBoundaryNoise; map = result2.map; const refineBoundary_result2 = refineBoundary(0, 10, tRect, map, size_x); map = refineBoundary_result2.result; const fillBlackComponent_result = fillBlackComponent(map, black_boundary, CONSTANTS.BLACK, size_x); map = fillBlackComponent_result.result; const filterSmallAreas_result = filterSmallAreas(map, tRect, size_x, size_y, m_four_Dir, m_eight_Dir); map = filterSmallAreas_result.result; const fillInternalObstacles_result = fillInternalObstacles(map, tRect, size_x); map = fillInternalObstacles_result.result; if (tMapStruct.info) { const roomColorByChainAndDoor_result = roomColorByChainAndDoor(tMapStruct.info, map, size_x, size_y, x_min, y_min, resolution); map = roomColorByChainAndDoor_result.map; } return { result: map }; } function findRoiMap(rect: Rect, map: Int8Array | Uint8Array, size_x: number, size_y: number): { result: Rect } { let top_bound = size_x; let bottom_bound = 0; let left_bound = size_y; let right_bound = 0; for (let idx = 0; idx < size_x; idx++) { for (let idy = 0; idy < size_y; idy++) { if (map[idy * size_x + idx] != 0) { if (left_bound > idy - 10) { if (idx - 10 >= 0) { left_bound = idy - 10; } else { left_bound = 0; } } else { break; } } } } for (let idx = 0; idx < size_x; idx++) { for (let idy = size_y - 1; idy > 0; idy--) { if (map[idy * size_x + idx] != 0) { if (right_bound < idy + 10) { if (idy + 10 < size_y) { right_bound = idy + 10; } else { right_bound = size_y - 1; } } else { break; } } } } for (let idy = 0; idy < size_y; idy++) { for (let idx = 0; idx < size_x; idx++) { if (map[idy * size_x + idx] != 0) { if (top_bound > idx - 10) { if (idx - 10 >= 0) { top_bound = idx - 10; } else { top_bound = 0; } } else { break; } } } } for (let idy = 0; idy < size_y; idy++) { for (let idx = size_x - 1; idx > 0; idx--) { if (map[idy * size_x + idx] != 0) { if (bottom_bound < idx + 10) { if (idx + 10 < size_x) { bottom_bound = idx + 10; } else { bottom_bound = size_x - 1; } } else { break; } } } } const width = right_bound - left_bound + 1; const height = bottom_bound - top_bound + 1; if (width > 0 && height > 0 && width < size_y && height < size_x) { rect.x = top_bound; rect.y = left_bound; rect.width = width; rect.height = height; return { result: rect }; } else { rect.x = 0; rect.y = 0; rect.width = size_y; rect.height = size_x; } return { result: rect }; } function expandBlackRect(kernel_size_x: number, kernel_size_y: number, threshold: number, rect: Rect, map: any, size_x: number, size_y: number): { result: any } { let il, ir, jl, jr; if (kernel_size_x % 2 == 1) { ir = (kernel_size_x - 1) >> 1; il = -ir; } else { ir = kernel_size_x >> 1; il = 1 - ir; } if (kernel_size_y % 2 == 1) { jr = (kernel_size_y - 1) >> 1; jl = -jr; } else { jr = kernel_size_y >> 1; jl = 1 - jr; } const dst = new Array(size_x * size_y).fill(CONSTANTS.WHITE); for (let i = rect.y; i < rect.y + rect.width; i++) { for (let j = rect.x; j < rect.x + rect.height; j++) { if (map[i * size_x + j] < threshold) { for (let di = il; di <= ir; di++) { for (let dj = jl; dj <= jr; dj++) { if (i + di < 0 || i + di >= rect.y + rect.width || j + dj < 0 || j + dj >= rect.x + rect.height) { continue; } if (dst[(i + di) * size_x + j + dj] > map[i * size_x + j]) { dst[(i + di) * size_x + j + dj] = map[i * size_x + j]; } } } } } } for (let i = 0; i < size_y; i++) { for (let j = 0; j < size_x; j++) { const index = i * size_x + j; if (dst[index] == CONSTANTS.WHITE) { dst[index] = map[index]; } } } map = dst; return { result: map }; } function expandWhiteRect(kernel_size_x: number, kernel_size_y: number, threshold: number, rect: Rect, map: any, size_x: number, size_y: number): { result: any } { let il, ir, jl, jr; if (kernel_size_x % 2 == 1) { ir = (kernel_size_x - 1) >> 1; il = -ir; } else { ir = kernel_size_x >> 1; il = 1 - ir; } if (kernel_size_y % 2 == 1) { jr = (kernel_size_y - 1) >> 1; jl = -jr; } else { jr = kernel_size_y >> 1; jl = 1 - jr; } const dst = new Array(size_x * size_y).fill(CONSTANTS.BLACK); for (let i = rect.y; i < rect.y + rect.width; i++) { for (let j = rect.x; j < rect.x + rect.height; j++) { if (map[i * size_x + j] > threshold) { for (let di = il; di <= ir; di++) { for (let dj = jl; dj <= jr; dj++) { if (i + di < 0 || i + di >= rect.y + rect.width || j + dj < 0 || j + dj >= rect.x + rect.height) { continue; } if (dst[(i + di) * size_x + j + dj] < map[i * size_x + j] && map[(i + di) * size_x + j + dj] < threshold) { dst[(i + di) * size_x + j + dj] = map[i * size_x + j]; } } } } } } for (let i = 0; i < size_y; i++) { for (let j = 0; j < size_x; j++) { const index = i * size_x + j; if (dst[index] == CONSTANTS.BLACK) { dst[index] = map[index]; } } } map = dst; return { result: map }; } function refineBoundary(threshold_black: number, threshold_white: number, rect: Rect, map: any, size_x: number): { result: any } { const Qx = []; const Qy = []; let hasWhiteNeighbor; for (let i = rect.y; i < rect.y + rect.width; i++) { for (let j = rect.x; j < rect.x + rect.height; j++) { if (map[i * size_x + j] < threshold_black) { hasWhiteNeighbor = false; for (let di = -1; di <= 1; di++) { for (let dj = -1; dj <= 1; dj++) { if (i + di < 0 || i + di >= rect.y + rect.width || j + dj < 0 || j + dj >= rect.x + rect.height) { continue; } if (map[(i + di) * size_x + j + dj] > threshold_white) { hasWhiteNeighbor = true; } } } if (!hasWhiteNeighbor) { Qx.push(i); Qy.push(j); } } } } for (let i = 0; i < Qx.length; i++) { map[Qx[i] * size_x + Qy[i]] = 0; } return { result: map }; } function eliminateNonBoundaryNoise(nonBoundaryNoise: Point[], rect: Rect, noise_color: number, border_color: number, outer_border_color: number, map: any, size_x: number): { map: any, tempnonBoundaryNoise: Point[] } { const tempnonBoundaryNoise = nonBoundaryNoise; for (let i = rect.y; i < rect.y + rect.width; i++) { for (let j = rect.x; j < rect.x + rect.height; j++) { if (map[i * size_x + j] == border_color) { if (i - 1 < 0 || i + 1 >= rect.y + rect.width || j - 1 < 0 || j + 1 >= rect.x + rect.height) { continue; } if (map[(i - 1) * size_x + j] != outer_border_color && map[(i + 1) * size_x + j] != outer_border_color && map[i * size_x + j - 1] != outer_border_color && map[i * size_x + j + 1] != outer_border_color && map[(i - 1) * size_x + j - 1] != outer_border_color && map[(i - 1) * size_x + j + 1] != outer_border_color && map[(i + 1) * size_x + j - 1] != outer_border_color && map[(i + 1) * size_x + j + 1] != outer_border_color) { map[i * size_x + j] = noise_color; tempnonBoundaryNoise.push(new Point(i, j)); } } } } return { map: map, tempnonBoundaryNoise: tempnonBoundaryNoise }; } function expandSingleConvexBoundary(external_corner_value: number, fill_value: number, valid_length: number, times: number, rect: Rect, map: any, size_x: number): { result: any } { try { let contour: Point[] = []; let contour_map = [...map]; const result = extractExternalContoursNewStrategy(contour_map, contour, rect, size_x); const isInBounds = (x: number, y: number) => ( x >= rect.x && x < rect.x + rect.height && y >= rect.y && y < rect.y + rect.width ); for (let i = 0; i < times; i++) { let extract_corners: Point[] = []; let fill_edges: Point[][] = []; const inner_corner_value = external_corner_value + 5; const four_neighbourhood = [[-1, 0], [1, 0], [0, -1], [0, 1]]; let delete_point: Point[] = []; contour_map = result.temp_map; contour = result.contour; const corner_map = [...map]; const result1 = extractCorners(corner_map, extract_corners, contour, external_corner_value, inner_corner_value, rect, map, size_x); let result2_delete_point: Point[] = []; result1.extract_corners.forEach((it: Point) => { let is_valid_length = false; const p_oint = it; for (let k = 0; k < 4; k++) { const temp_idy = p_oint.x + four_neighbourhood[k][0]; const temp_idx = p_oint.y + four_neighbourhood[k][1]; if (!isInBounds(temp_idx, temp_idy)) { continue; } if (result1.corner_map[temp_idy * size_x + temp_idx] == inner_corner_value) { const near_inner_p_oint = new Point(temp_idy, temp_idx); const resultInner = statisticalLineLength(result1.corner_map, near_inner_p_oint, external_corner_value, inner_corner_value, valid_length, rect, size_x); is_valid_length = resultInner.result; break; } if (k == 3) { is_valid_length = true; } } const fourNeighbourhoodSearchForExtractCorners_result = fourNeighbourhoodSearchForExtractCorners(result1.corner_map, p_oint, fill_edges, delete_point, external_corner_value, inner_corner_value, valid_length, is_valid_length, rect, map, size_x); const result2Internal = fourNeighbourhoodSearchForExtractCorners_result.result; fill_edges = result2Internal.fill_edges; result2_delete_point = result2Internal.delete_point; map = result2Internal.map; }); const arrResult = updateContour(contour, result2_delete_point); const array = arrResult.result; const result3 = fillEdges(map, array, fill_edges, fill_value, size_x); map = result3.map; contour = result3.contour; delete_point = []; extract_corners = []; fill_edges = []; } contour = []; return { result: map }; } catch (e: any) { console.error("expandSingle CRASH:", e); throw e; } } function extractExternalContoursNewStrategy(temp_map: any, contour: Point[], rect: Rect, size_x: number): { temp_map: any, contour: Point[] } { let gray_region: Point[] = []; const result = findGrayConnectComponent(temp_map, gray_region, rect, size_x); gray_region = result.gray_region; temp_map = result.temp_map; const result1 = findExternalContoursNewStrategy(temp_map, gray_region, contour, rect, size_x); return { temp_map: result1.temp_map, contour: result1.contour }; } function findGrayConnectComponent(temp_map: any, gray_region: Point[], rect: Rect, size_x: number): { gray_region: Point[], temp_map: any } { const four_neighbourhood = [[-1, 0], [0, 1], [1, 0], [0, -1]]; let findOnePoint = false; const isInBounds = (x: number, y: number) => ( x >= rect.x && x < rect.x + rect.height && y >= rect.y && y < rect.y + rect.width ); for (let idy = rect.y; idy < rect.y + rect.width; idy++) { for (let idx = rect.x; idx < rect.x + rect.height; idx++) { if (temp_map[idy * size_x + idx] == 0) { findOnePoint = true; const p_oint_for_search: Point[] = []; gray_region.push(new Point(idy, idx)); p_oint_for_search.push(new Point(idy, idx)); temp_map[idy * size_x + idx] = 30; let index = 0; while (index < p_oint_for_search.length) { const seed = p_oint_for_search[index]; index++; for (let k = 0; k < 4; k++) { const temp_idy = seed.x + four_neighbourhood[k][0]; const temp_idx = seed.y + four_neighbourhood[k][1]; if (!isInBounds(temp_idx, temp_idy)) { continue; } if (temp_map[temp_idy * size_x + temp_idx] == 0) { temp_map[temp_idy * size_x + temp_idx] = 30; p_oint_for_search.push(new Point(temp_idy, temp_idx)); gray_region.push(new Point(temp_idy, temp_idx)); } } } } if (findOnePoint) { break; } } if (findOnePoint) { findOnePoint = false; break; } } return { gray_region: gray_region, temp_map: temp_map }; } function findExternalContoursNewStrategy(temp_map: any, gray_region: Point[], contour: Point[], rect: Rect, size_x: number): { temp_map: any, contour: Point[] } { const eight_neighbourhood = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, 1], [1, 1], [1, -1], [-1, -1]]; const isInBounds = (x: number, y: number) => ( x >= rect.x && x < rect.x + rect.height && y >= rect.y && y < rect.y + rect.width ); for (let i = 0; i < gray_region.length; i++) { for (let k = 0; k < 8; k++) { const temp_idy = gray_region[i].x + eight_neighbourhood[k][0]; const temp_idx = gray_region[i].y + eight_neighbourhood[k][1]; if (!isInBounds(temp_idx, temp_idy)) { continue; } if (temp_map[temp_idy * size_x + temp_idx] == CONSTANTS.BLACK) { temp_map[temp_idy * size_x + temp_idx] = 40; contour.push(new Point(temp_idy, temp_idx)); } } } return { temp_map: temp_map, contour: contour }; } function extractCorners(corner_map: any, extract_corner: Point[], contour: Point[], external_corner_value: number, inner_corner_value: number, rect: Rect, map: any, size_x: number): { corner_map: any, extract_corners: Point[] } { const four_neighbourhood = [[-1, 0], [0, 1], [1, 0], [0, -1]]; const temp_map = [...map]; const isInBounds = (x: number, y: number) => ( x >= rect.x && x < rect.x + rect.height && y >= rect.y && y < rect.y + rect.width ); for (let i = 0; i < contour.length; i++) { let black_count = 0; let white_count = 0; let gray_count = 0; for (let k = 0; k < 4; k++) { const temp_idy = contour[i].x + four_neighbourhood[k][0]; const temp_idx = contour[i].y + four_neighbourhood[k][1]; if (!isInBounds(temp_idx, temp_idy)) { continue; } if (temp_map[temp_idy * size_x + temp_idx] === CONSTANTS.BLACK) { black_count++; } else if (temp_map[temp_idy * size_x + temp_idx] == 0) { gray_count++; } else if (temp_map[temp_idy * size_x + temp_idx] == CONSTANTS.WHITE) { white_count++; } if (gray_count == 2 && black_count == 2) { extract_corner.push(new Point(contour[i].x, contour[i].y)); corner_map[contour[i].x * size_x + contour[i].y] = external_corner_value; } else if ((white_count == 2) && (black_count == 2)) { corner_map[contour[i].x * size_x + contour[i].y] = inner_corner_value; } } } return { corner_map: corner_map, extract_corners: extract_corner }; } function statisticalLineLength(temp_map: any, p_oint: Point, external_corner_value: number, inner_corner_value: number, valid_length: number, rect: Rect, size_x: number): { result: boolean } { const result1 = upSearchStatisticalLineLength(temp_map, p_oint, external_corner_value, inner_corner_value, valid_length, rect, size_x); if (result1.result) { return { result: true }; } const result2 = downSearchStatisticalLineLength(temp_map, p_oint, external_corner_value, inner_corner_value, valid_length, rect, size_x); if (result2.result) { return { result: true }; } const result3 = leftSearchStatisticalLineLength(temp_map, p_oint, external_corner_value, inner_corner_value, valid_length, rect, size_x); if (result3.result) { return { result: true }; } const result4 = rightSearchStatisticalLineLength(temp_map, p_oint, external_corner_value, inner_corner_value, valid_length, rect, size_x); if (result4.result) { return { result: true }; } return { result: false }; } function upSearchStatisticalLineLength(temp_map: any, p_oint: Point, external_corner_value: number, inner_corner_value: number, valid_length: number, rect: Rect, size_x: number): { result: boolean } { if ((p_oint.x + 1 < rect.y + rect.width) && (temp_map[(p_oint.x + 1) * size_x + p_oint.y]) == CONSTANTS.WHITE) { const idy = p_oint.x + 1; const idx = p_oint.y; const line = []; line.push(new Point(idy, idx)); for (let j = idy; j < rect.y + rect.width; j++) { if (temp_map[j * size_x + idx] == CONSTANTS.WHITE) { let black_count = 0; const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = j + left_and_right_neighbourhood[k][0]; const tmp_idx = idx + left_and_right_neighbourhood[k][1]; const maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < rect.y || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(j, idx)); } else { break; } } else { break; } } if (line.length > valid_length) { return { result: true }; } else { return { result: false }; } } return { result: false }; } function downSearchStatisticalLineLength(temp_map: any, p_oint: Point, external_corner_value: number, inner_corner_value: number, valid_length: number, rect: Rect, size_x: number): { result: boolean } { if ((p_oint.x - 1 > rect.y) && (temp_map[(p_oint.x - 1) * size_x + p_oint.y] == CONSTANTS.WHITE)) { const idy = p_oint.x - 1; const idx = p_oint.y; const line = []; line.push(new Point(idy, idx)); for (let j = idy; j > rect.y; j--) { if (temp_map[j * size_x + idx] == CONSTANTS.WHITE) { let black_count = 0; const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = j + left_and_right_neighbourhood[k][0]; const tmp_idx = idx + left_and_right_neighbourhood[k][1]; const maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < rect.y || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(j, idx)); } else { break; } } else { break; } } return { result: line.length > valid_length }; } return { result: false }; } function leftSearchStatisticalLineLength(temp_map: any, p_oint: Point, external_corner_value: number, inner_corner_value: number, valid_length: number, rect: Rect, size_x: number): { result: boolean } { if ((p_oint.y + 1 < rect.x + rect.height) && (temp_map[p_oint.x * size_x + p_oint.y + 1] == CONSTANTS.WHITE)) { const idy = p_oint.x; const idx = p_oint.y + 1; const line = []; line.push(new Point(idy, idx)); for (let j = idx; j < rect.x + rect.height; j++) { if (temp_map[idy * size_x + j] == CONSTANTS.WHITE) { let black_count = 0; const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = idy + up_and_down_neighbourhood[k][0]; const tmp_idx = j + up_and_down_neighbourhood[k][1]; const maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < rect.y || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(idy, j)); } else { break; } } else { break; } } return { result: line.length > valid_length }; } return { result: false }; } function rightSearchStatisticalLineLength(temp_map: any, p_oint: Point, external_corner_value: number, inner_corner_value: number, valid_length: number, rect: Rect, size_x: number): { result: boolean } { if ((p_oint.y - 1 > rect.x) && (temp_map[p_oint.x * size_x + p_oint.y - 1] == CONSTANTS.WHITE)) { const idy = p_oint.x; const idx = p_oint.y - 1; const line = []; line.push(new Point(idy, idx)); for (let j = idx; j > rect.x; j--) { if (temp_map[idy * size_x + j] == CONSTANTS.WHITE) { let black_count = 0; const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = idy + up_and_down_neighbourhood[k][0]; const tmp_idx = j + up_and_down_neighbourhood[k][1]; const maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < rect.y || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(idy, j)); } else { break; } } else { break; } } return { result: line.length > valid_length }; } return { result: false }; } function fourNeighbourhoodSearchForExtractCorners(temp_map: any, p_oint: Point, fill_edges: Point[][], delete_point: Point[], external_corner_value: number, inner_corner_value: number, valid_length: number, is_valid_length: boolean, rect: Rect, map: any, size_x: number): { result: any } { const result1 = upSearchForExtractCorners(temp_map, p_oint, fill_edges, delete_point, external_corner_value, inner_corner_value, valid_length, is_valid_length, rect, map, size_x); const result2 = downSearchForExtractCorners(temp_map, p_oint, result1.fill_edges, result1.delete_point, external_corner_value, inner_corner_value, valid_length, is_valid_length, rect, result1.map, size_x); const result3 = leftSearchForExtractCorners(temp_map, p_oint, result2.fill_edges, result2.delete_point, external_corner_value, inner_corner_value, valid_length, is_valid_length, rect, result2.map, size_x); const result4 = rightSearchForExtractCorners(temp_map, p_oint, result3.fill_edges, result3.delete_point, external_corner_value, inner_corner_value, valid_length, is_valid_length, rect, result3.map, size_x); return { result: result4 }; } function upSearchForExtractCorners(temp_map: any, p_oint: Point, fill_edges: Point[][], delete_point: Point[], external_corner_value: number, inner_corner_value: number, valid_length: number, is_valid_length: boolean, rect: Rect, map: any, size_x: number): { delete_point: Point[], fill_edges: Point[][], map: any } { if ((p_oint.x + 1 < rect.y + rect.width) && map[(p_oint.x + 1) * size_x + p_oint.y] == 0) { const idy = p_oint.x + 1; const idx = p_oint.y; let line: Point[] = []; line.push(new Point(idy, idx)); for (let j = idy; j < rect.y + rect.width; j++) { if (temp_map[j * size_x + idx] == 0) { let black_count = 0; const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = j + left_and_right_neighbourhood[k][0]; const tmp_idx = idx + left_and_right_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < minY || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(j, idx)); } else { break; } } else { break; } } if (is_valid_length && line.length > 1) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + left_and_right_neighbourhood[k][0]; const tmp_idx = line[i].y + left_and_right_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < minY || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else if (line.length > valid_length) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + left_and_right_neighbourhood[k][0]; const tmp_idx = line[i].y + left_and_right_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < minY || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else { line = []; } } return { delete_point: delete_point, fill_edges: fill_edges, map: map }; } function downSearchForExtractCorners(temp_map: any, p_oint: Point, fill_edges: Point[][], delete_point: Point[], external_corner_value: number, inner_corner_value: number, valid_length: number, is_valid_length: boolean, rect: Rect, map: any, size_x: number): { delete_point: Point[], fill_edges: Point[][], map: any } { if ((p_oint.x - 1 > rect.y) && (map[(p_oint.x - 1) * size_x + p_oint.y] == 0)) { const idy = p_oint.x - 1; const idx = p_oint.y; let line: Point[] = []; line.push(new Point(idy, idx)); for (let j = idy; j > rect.y; j--) { if (temp_map[j * size_x + idx] == 0) { let black_count = 0; const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = j + left_and_right_neighbourhood[k][0]; const tmp_idx = idx + left_and_right_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < minY || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(j, idx)); } else { break; } } else { break; } } if (is_valid_length && line.length > 1) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + left_and_right_neighbourhood[k][0]; const tmp_idx = line[i].y + left_and_right_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < minY || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else if (line.length > valid_length) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const left_and_right_neighbourhood = [[0, -1], [0, 1]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + left_and_right_neighbourhood[k][0]; const tmp_idx = line[i].y + left_and_right_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < minY || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else { line = []; } } return { delete_point: delete_point, fill_edges: fill_edges, map: map }; } function leftSearchForExtractCorners(temp_map: any, p_oint: Point, fill_edges: Point[][], delete_point: Point[], external_corner_value: number, inner_corner_value: number, valid_length: number, is_valid_length: boolean, rect: Rect, map: any, size_x: number): { delete_point: Point[], fill_edges: Point[][], map: any } { if ((p_oint.y + 1 < rect.x + rect.height) && (map[p_oint.x * size_x + p_oint.y + 1] == 0)) { const idy = p_oint.x; const idx = p_oint.y + 1; let line: Point[] = []; line.push(new Point(idy, idx)); for (let j = idx; j < rect.x + rect.height; j++) { if (temp_map[idy * size_x + j] == 0) { let black_count = 0; const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = idy + up_and_down_neighbourhood[k][0]; const tmp_idx = j + up_and_down_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < minY || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(idy, j)); } else { break; } } else { break; } } if (is_valid_length && line.length > 1) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + up_and_down_neighbourhood[k][0]; const tmp_idx = line[i].y + up_and_down_neighbourhood[k][1]; const maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < rect.y || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else if (line.length > valid_length) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + up_and_down_neighbourhood[k][0]; const tmp_idx = line[i].y + up_and_down_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idy < minY || tmp_idy >= maxY || tmp_idx < minX || tmp_idx >= maxX) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else { line = []; } } return { delete_point: delete_point, fill_edges: fill_edges, map: map }; } function rightSearchForExtractCorners(temp_map: any, p_oint: Point, fill_edges: Point[][], delete_point: Point[], external_corner_value: number, inner_corner_value: number, valid_length: number, is_valid_length: boolean, rect: Rect, map: any, size_x: number): { delete_point: Point[], fill_edges: Point[][], map: any } { if ((p_oint.y - 1 > rect.x) && (map[p_oint.x * size_x + p_oint.y - 1] == 0)) { const idy = p_oint.x; const idx = p_oint.y - 1; let line: Point[] = []; line.push(new Point(idy, idx)); for (let j = idx; j > rect.x; j--) { if (temp_map[idy * size_x + j] == 0) { let black_count = 0; const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = idy + up_and_down_neighbourhood[k][0]; const tmp_idx = j + up_and_down_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < minY || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == external_corner_value || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { black_count++; } } if (black_count == 1) { line.push(new Point(idy, j)); } else { break; } } else { break; } } if (is_valid_length && line.length > 1) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + up_and_down_neighbourhood[k][0]; const tmp_idx = line[i].y + up_and_down_neighbourhood[k][1]; const minY = rect.y, maxY = rect.y + rect.width; const minX = rect.x, maxX = rect.x + rect.height; if (tmp_idx < minX || tmp_idx >= maxX || tmp_idy < minY || tmp_idy >= maxY) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else if (line.length > valid_length) { line.push(p_oint); fill_edges.push(line); for (let i = 0; i < line.length; i++) { const up_and_down_neighbourhood = [[-1, 0], [1, 0]]; for (let k = 0; k < 2; k++) { const tmp_idy = line[i].x + up_and_down_neighbourhood[k][0]; const tmp_idx = line[i].y + up_and_down_neighbourhood[k][1]; if (tmp_idx < rect.x || tmp_idx >= rect.x + rect.height || tmp_idy < rect.y || tmp_idy >= rect.y + rect.width) { continue; } if (temp_map[tmp_idy * size_x + tmp_idx] == CONSTANTS.BLACK || temp_map[tmp_idy * size_x + tmp_idx] == inner_corner_value) { map[tmp_idy * size_x + tmp_idx] = CONSTANTS.WHITE; delete_point.push(new Point(tmp_idy, tmp_idx)); } } } } else { line = []; } } return { delete_point: delete_point, fill_edges: fill_edges, map: map }; } function updateContour(contour: Point[], delete_points: Point[]): { result: Point[] } { const delete_point_size = delete_points.length; for (let i = 0; i < delete_point_size; i++) { const delete_point = delete_points[i]; contour = contour.filter((it: Point) => !(it.x === delete_point.x && it.y === delete_point.y)); } return { result: contour }; } function fillEdges(map: any, contour: Point[], fill_edges: Point[][], value: number, size_x: number): { contour: Point[], map: any } { for (let i = 0; i < fill_edges.length; i++) { const edge = fill_edges[i]; for (let j = 0; j < edge.length; j++) { map[edge[j].x * size_x + edge[j].y] = value; contour.push(edge[j]); } } return { contour: contour, map: map }; } function findWhiteConnectComponent(all_region: { first: Point[], second: Point[] }[], valid_area: number, rect: Rect, size_x: number, map: any): { result: { first: Point[], second: Point[] }[] } { let temp_map = [...map]; const four_neighbourhood = [[-1, 0], [0, 1], [1, 0], [0, -1]]; const isInBounds = (x: number, y: number) => ( x >= rect.x && x < rect.x + rect.height && y >= rect.y && y < rect.y + rect.width ); for (let idy = rect.y + 1; idy < rect.y + rect.width - 1; idy++) { for (let idx = rect.x + 1; idx < rect.x + rect.height - 1; idx++) { if (temp_map[idy * size_x + idx] == CONSTANTS.WHITE) { const tmp_white_region: Point[] = []; let tmp_black_region: Point[] = []; const p_oint_for_search: Point[] = []; tmp_white_region.push(new Point(idy, idx)); p_oint_for_search.push(new Point(idy, idx)); temp_map[idy * size_x + idx] = 30; let pointIndex = 0; while (pointIndex < p_oint_for_search.length) { // 删除数组中的第一个元素并返回删除的元素 const seed = p_oint_for_search[pointIndex]; pointIndex++; const result = findBlackTPoint(temp_map, seed, tmp_black_region, size_x, rect); temp_map = result.temp_map; tmp_black_region = result.tmp_black_region; for (let k = 0; k < 4; k++) { const temp_idy = seed.x + four_neighbourhood[k][0]; const temp_idx = seed.y + four_neighbourhood[k][1]; if (!isInBounds(temp_idx, temp_idy)) { continue; } if (temp_map[temp_idy * size_x + temp_idx] == CONSTANTS.WHITE) { temp_map[temp_idy * size_x + temp_idx] = 30; p_oint_for_search.push(new Point(temp_idy, temp_idx)); tmp_white_region.push(new Point(temp_idy, temp_idx)); } } } all_region.push({ first: tmp_black_region, second: tmp_white_region }); } } } const tempAll_region: { first: Point[], second: Point[] }[] = []; for (let i = 0; i < all_region.length; i++) { const temp = all_region[i]; if (temp.second.length < valid_area || temp.first.length == 0 || temp.second.length == 0) { } else { tempAll_region.push(temp); } } all_region = tempAll_region; if (all_region.length > 0) { all_region.sort((a, b) => b.first.length - a.first.length); } return { result: all_region }; } function findBlackTPoint(temp_map: any, seed: Point, black_region: Point[], size_x: number, tRect: Rect): { temp_map: any, tmp_black_region: Point[] } { const eight_neighbourhood = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, 1], [1, 1], [1, -1], [-1, -1]]; for (let k = 0; k < 8; k++) { const temp_idy = seed.x + eight_neighbourhood[k][0]; const temp_idx = seed.y + eight_neighbourhood[k][1]; if (temp_idy < tRect.y || temp_idy >= tRect.y + tRect.width || temp_idx < tRect.x || temp_idx >= tRect.x + tRect.height) { continue; } if (temp_map[temp_idy * size_x + temp_idx] == CONSTANTS.BLACK) { temp_map[temp_idy * size_x + temp_idx] = 10; black_region.push(new Point(temp_idy, temp_idx)); } } return { temp_map: temp_map, tmp_black_region: black_region, }; } function removeIndependentRegion(all_region: { first: Point[], second: Point[] }[], black_boundary: Point[], valid_length: number, rect: Rect, map: any, size_x: number): { temp_black_boundary: Point[], map: any } { let temp_black_boundary = black_boundary; if (all_region.length > 0) { let temp_map = [...map]; const tmp_all_region: { first: Point[], second: Point[] }[] = []; const temp_map_result = fillBlackComponent(temp_map, all_region[0].first, 30, size_x); temp_map = temp_map_result.result; tmp_all_region.push(all_region[0]); const result = { temp_map: temp_map, black_boundary: black_boundary, }; for (let i = 1; i < all_region.length; i++) { let is_home = false; const black_boundary_size = all_region[i].first.length; for (let j = 0; j < black_boundary_size; j++) { let search_success = false; const seed = all_region[i].first[j]; const tempResult = fourNeighbourhoodSearchArea(result.temp_map, seed, result.black_boundary, 30, valid_length, rect, size_x); search_success = tempResult.boolStatus; temp_black_boundary = tempResult.black_boundary; result.temp_map = tempResult.temp_map; result.black_boundary = tempResult.black_boundary; if (search_success) { is_home = true; } } if (is_home) { tmp_all_region.push(all_region[i]); } } const fillConnectComponent_result = fillConnectComponent(result.temp_map, tmp_all_region, 30, size_x); result.temp_map = fillConnectComponent_result.result; for (let idy = rect.y + 1; idy < rect.y + rect.width - 1; idy++) { for (let idx = rect.x + 1; idx < rect.x + rect.height - 1; idx++) { if (result.temp_map[idy * size_x + idx] != 0 && result.temp_map[idy * size_x + idx] != 30) { map[idy * size_x + idx] = 0; } } } } return { temp_black_boundary: temp_black_boundary, map: map }; } function fillConnectComponent(temp_map: any, all_region: { first: Point[], second: Point[] }[], value: number, size_x: number): { result: any } { for (let i = 0; i < all_region.length; i++) { for (let j = 0; j < all_region[i].first.length; j++) { temp_map[all_region[i].first[j].x * size_x + all_region[i].first[j].y] = value; } for (let j2 = 0; j2 < all_region[i].second.length; j2++) { temp_map[all_region[i].second[j2].x * size_x + all_region[i].second[j2].y] = value; } } return { result: temp_map }; } interface SearchAreaResult { boolStatus: boolean; line: Point[]; } function fourNeighbourhoodSearchArea(temp_map: any, p_oint: Point, black_boundary: Point[], boundary_value: number, valid_length: number, rect: Rect, size_x: number): { temp_map: any, black_boundary: Point[], boolStatus: boolean } { let up_result: SearchAreaResult = { boolStatus: false, line: [] }; let down_result: SearchAreaResult = { boolStatus: false, line: [] }; let left_result: SearchAreaResult = { boolStatus: false, line: [] }; let right_result: SearchAreaResult = { boolStatus: false, line: [] }; up_result = upSearchArea(temp_map, p_oint, boundary_value, valid_length, rect, size_x); down_result = downSearchArea(temp_map, p_oint, boundary_value, valid_length, rect, size_x); left_result = leftSearchArea(temp_map, p_oint, boundary_value, valid_length, rect, size_x); right_result = rightSearchArea(temp_map, p_oint, boundary_value, valid_length, rect, size_x); if (up_result.boolStatus || down_result.boolStatus || left_result.boolStatus || right_result.boolStatus) { if (up_result.line.length > 0) { for (let i = 0; i < up_result.line.length; i++) { black_boundary.push(up_result.line[i]); } } if (down_result.line.length > 0) { for (let i = 0; i < down_result.line.length; i++) { black_boundary.push(down_result.line[i]); } } if (left_result.line.length > 0) { for (let i = 0; i < left_result.line.length; i++) { black_boundary.push(left_result.line[i]); } } if (right_result.line.length > 0) { for (let i = 0; i < right_result.line.length; i++) { black_boundary.push(right_result.line[i]); } } return { temp_map: temp_map, black_boundary: black_boundary, boolStatus: true }; } else { return { temp_map: temp_map, black_boundary: black_boundary, boolStatus: false }; } } function upSearchArea(temp_map: any, p_oint: Point, boundary_value: number, valid_length: number, rect: Rect, size_x: number): SearchAreaResult { if ((p_oint.y + 1 < rect.x + rect.height) && (temp_map[p_oint.x * size_x + p_oint.y + 1] == 0)) { const idy = p_oint.x; const idx = p_oint.y + 1; let line: Point[] = []; line.push(new Point(idy, idx)); let has_black_boundary = false; for (let j = idx; j < idx + valid_length; j++) { if (j >= rect.x + rect.height) { continue; } if (temp_map[idy * size_x + j] == boundary_value) { has_black_boundary = true; break; } else if (temp_map[idy * size_x + j] == CONSTANTS.WHITE || temp_map[idy * size_x + j] == CONSTANTS.BLACK) { line = []; break; } else if (temp_map[idy * size_x + j] == 0) { line.push(new Point(idy, j)); } } if (has_black_boundary) { return { boolStatus: true, line: line }; } else { line = []; return { boolStatus: false, line: line }; } } return { boolStatus: false, line: [] }; } function downSearchArea(temp_map: any, p_oint: Point, boundary_value: number, valid_length: number, rect: Rect, size_x: number): SearchAreaResult { if ((p_oint.y - 1 > rect.x) && (temp_map[p_oint.x * size_x + p_oint.y - 1] == 0)) { const idy = p_oint.x; const idx = p_oint.y - 1; let line: Point[] = []; line.push(new Point(idy, idx)); let has_black_boundary = false; for (let j = idx; j > idx - valid_length; j--) { if (j < rect.x) { continue; } if (temp_map[idy * size_x + j] == boundary_value) { has_black_boundary = true; break; } else if (temp_map[idy * size_x + j] == CONSTANTS.WHITE || temp_map[idy * size_x + j] == CONSTANTS.BLACK) { line = []; break; } else if (temp_map[idy * size_x + j] == 0) { line.push(new Point(idy, j)); } } if (has_black_boundary) { return { boolStatus: true, line: line }; } else { line = []; return { boolStatus: false, line: line }; } } return { boolStatus: false, line: [] }; } function leftSearchArea(temp_map: any, p_oint: Point, boundary_value: number, valid_length: number, rect: Rect, size_x: number) { if ((p_oint.x + 1 < rect.y + rect.width) && (temp_map[(p_oint.x + 1) * size_x + p_oint.y] == 0)) { const idy = p_oint.x + 1; const idx = p_oint.y; let line: Point[] = []; line.push(new Point(idy, idx)); let has_black_boundary = false; for (let j = idy; j < idy + valid_length; j++) { if (j >= rect.y + rect.width) { continue; } if (temp_map[j * size_x + idx] == boundary_value) { has_black_boundary = true; break; } else if (temp_map[j * size_x + idx] == CONSTANTS.WHITE || temp_map[j * size_x + idx] == CONSTANTS.BLACK) { line = []; break; } else if (temp_map[j * size_x + idx] == 0) { line.push(new Point(j, idx)); } } if (has_black_boundary) { return { boolStatus: true, line: line }; } else { line = []; return { boolStatus: false, line: line }; } } return { boolStatus: false, line: [] }; } function rightSearchArea(temp_map: any, p_oint: Point, boundary_value: number, valid_length: number, rect: Rect, size_x: number) { if ((p_oint.x - 1 > rect.y) && (temp_map[(p_oint.x - 1) * size_x + p_oint.y] == 0)) { const idy = p_oint.x - 1; const idx = p_oint.y; let line: Point[] = []; line.push(new Point(idy, idx)); let has_black_boundary = false; for (let j = idy; j > idy - valid_length; j--) { if (j <= rect.y) { continue; } if (temp_map[j * size_x + idx] == boundary_value) { has_black_boundary = true; break; } else if (temp_map[j * size_x + idx