// 定义雷达坐标系中的矩形接口 export interface RadarRect { x_cm_start: number x_cm_stop: number y_cm_start: number y_cm_stop: number } // 定义画布坐标系中的矩形接口 export interface CanvasRect { left: number top: number width: number height: number } // 定义雷达在画布中的位置接口 export interface RadarPosition { x_radar: number y_radar: number } // 定义家具在雷达坐标系中的接口 export interface RadarFurniture { x: number y: number width: number height: number } /** * 检测区域、子区域 矩形转换 雷达坐标系 --> 画布坐标系 * @param src_rect - 雷达坐标系矩形 * @param p_radar - 画布中雷达的位置 * @returns CSS 可用矩形 */ export function convert_region_r2c(src_rect: RadarRect, p_radar: RadarPosition): CanvasRect { const x_radar = p_radar.x_radar const y_radar = p_radar.y_radar const left = x_radar + src_rect.x_cm_start const top = y_radar - src_rect.y_cm_stop const width = src_rect.x_cm_stop - src_rect.x_cm_start const height = src_rect.y_cm_stop - src_rect.y_cm_start return { left, top, width, height } } /** * 检测区域、子区域 矩形转换 画布坐标系 --> 雷达坐标系 * @param dst_rect - 画布矩形 * @param p_radar - 雷达在画布坐标系中的位置 * @returns 雷达坐标矩形 */ export function convert_region_c2r(dst_rect: CanvasRect, p_radar: RadarPosition): RadarRect { const x_radar = p_radar.x_radar const y_radar = p_radar.y_radar const x_cm_start = dst_rect.left - x_radar const x_cm_stop = x_cm_start + dst_rect.width const y_cm_stop = y_radar - dst_rect.top const y_cm_start = y_cm_stop - dst_rect.height return { x_cm_start, x_cm_stop, y_cm_start, y_cm_stop, } } /** * 家具 矩形转换 雷达坐标系 --> 画布坐标系 * @param furniture - 雷达坐标家具对象 * @param p_radar - 雷达在画布上的坐标 * @returns CSS 可用家具矩形 */ export function convert_furniture_r2c( furniture: RadarFurniture, p_radar: RadarPosition ): CanvasRect { const x_radar = p_radar.x_radar const y_radar = p_radar.y_radar const left = x_radar + furniture.x const top = y_radar - furniture.y const width = furniture.width const height = furniture.height return { left, top, width, height, } } /** * 家具 矩形转换 画布坐标系 --> 雷达坐标系 * @param furniture_item - 画布矩形(CSS) * @param p_radar - 雷达在画布上的坐标 * @returns 雷达坐标家具矩形 */ export function convert_furniture_c2r( furniture_item: CanvasRect, p_radar: RadarPosition ): RadarFurniture { const x_radar = p_radar.x_radar const y_radar = p_radar.y_radar const x = furniture_item.left - x_radar const y = y_radar - furniture_item.top const width = furniture_item.width const height = furniture_item.height return { x, y, width, height, } } /* ===================== 旋转方法 =================================== */ interface Rect { left: number top: number width: number height: number } interface Point { x: number y: number } /** * 顺时针旋转矩形 * @param src_rect - 输入矩形 { left, top, width, height } * @param pRadar - 雷达中心坐标 { x, y } * @param angle - 顺时针旋转角度 0, 90, 180, 270 * @returns 旋转后的矩形 { left, top, width, height } */ export function rotateRect_cw(src_rect: Rect, pRadar: Point, angle: number): Rect { if (![0, 90, 180, 270].includes(angle)) angle = 0 const { left, top, width, height } = src_rect const cx = left + width / 2 const cy = top + height / 2 const dx = cx - pRadar.x const dy = cy - pRadar.y let new_dx: number = 0 let new_dy: number = 0 switch (angle) { case 0: new_dx = dx new_dy = dy break case 90: new_dx = -dy new_dy = dx break case 180: new_dx = -dx new_dy = -dy break case 270: new_dx = dy new_dy = -dx break } const new_cx = pRadar.x + new_dx const new_cy = pRadar.y + new_dy let new_width = width let new_height = height if (angle === 90 || angle === 270) { new_width = height new_height = width } return { left: new_cx - new_width / 2, top: new_cy - new_height / 2, width: new_width, height: new_height, } } /** * 逆时针旋转矩形(家具/检测区域) * @param src_rect - 输入矩形 { left, top, width, height } * @param pRadar - 雷达中心坐标 { x, y } * @param angle - 逆时针旋转角度 0, 90, 180, 270 * @returns 旋转后的矩形 { left, top, width, height } */ export function rotateRect_ccw(src_rect: Rect, pRadar: Point, angle: number): Rect { if (![0, 90, 180, 270].includes(angle)) angle = 0 const { left, top, width, height } = src_rect const cx = left + width / 2 const cy = top + height / 2 const dx = cx - pRadar.x const dy = cy - pRadar.y let new_dx: number = 0 let new_dy: number = 0 switch (angle) { case 0: new_dx = dx new_dy = dy break case 90: new_dx = dy new_dy = -dx break case 180: new_dx = -dx new_dy = -dy break case 270: new_dx = -dy new_dy = dx break } const new_cx = pRadar.x + new_dx const new_cy = pRadar.y + new_dy let new_width = width let new_height = height if (angle === 90 || angle === 270) { new_width = height new_height = width } return { left: new_cx - new_width / 2, top: new_cy - new_height / 2, width: new_width, height: new_height, } } interface Point { x: number y: number } /** * 将雷达坐标系中的点转换到画布坐标系(旋转 + 平移) * @param src_point - 雷达坐标系中的点 * @param pRadar - 雷达在画布坐标系中的坐标 * @param angle - 雷达顺时针旋转角度(度) * @returns 画布坐标系中的点 */ export function convert_point_r2c(src_point: Point, pRadar: Point, angle: number): Point { const rad = (angle * Math.PI) / 180 // 角度转弧度(顺时针为正) const cosA = Math.cos(rad) const sinA = Math.sin(rad) // 顺时针旋转 const xRot = src_point.x * cosA + src_point.y * sinA const yRot = -src_point.x * sinA + src_point.y * cosA // 平移到画布坐标系 return { x: pRadar.x + xRot, y: pRadar.y - yRot, } }