iobroker.roborock
Version:
1,548 lines (1,340 loc) • 87.5 kB
text/typescript
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