平面坐标归一化

平面坐标归一化是将数据按照一定的比例缩放,使得数据的范围在0到1之间。
平面坐标归一化主要包括两个步骤,计算最小值和范围,以及对每个数据点进行缩放。具体实现如下:

  • 计算最小值和范围: 首先需要找到所有数据中最小的x和y值,以及x和y的范围(即最大值减去最小值)。可以遍历每个数据点找到最小值和范围,也可以使用numpy库中的min、max和ptp函数来计算。

  • 对每个数据点进行缩放: 对于每个数据点(x,y),可以使用以下公式将其缩放至0到1之间:

new_x = (x - min_x) / range_x 
new_y = (y - min_y) / range_y

其中,min_x和min_y是步骤1中计算出的x和y的最小值,range_x和range_y是x和y的范围。

通过这样的处理,可以将平面坐标归一化为0到1之间的数值,方便后续的计算和分析。

本文介绍如何实现平面坐标归一化,支持-1到1之间,效果如下

包围盒

包围盒就是一个能够完全包含住一个物体的盒子,通常是一个长方体或正方体。它可以用一些参数来描述,比如中心点、长度、宽度、高度等。 获取点坐标的最大最小值,如下

const boundingBox = [
    Math.min(...points.map(i => i.x)),
    Math.max(...points.map(i => i.x)),
    Math.min(...points.map(i => i.y)),
    Math.max(...points.map(i => i.y)),
]

计算包围盒宽和高,如果不想让绘制区域铺满整个屏幕,或者说想留边距,可以像下面这样配置

// 包围盒长、宽,20是边距
const boundingBoxWidth = boundingBox[1] - boundingBox[0] + 20
const boundingBoxHeight = boundingBox[3] - boundingBox[2] + 20

点坐标归一化

计算缩放比,然后将点坐标归一化

// 高宽的比值, 此案例中boundingBoxHeight > boundingBoxWidth,因此使用高度为缩放标准
const aspectRatio = boundingBoxWidth/boundingBoxHeight
    // 高度归一化之后还原需要放大的倍数
    let heightRito = h/2, widthRito = w/2;
if ((boundingBoxWidth/boundingBoxHeight) < (w/h)) {
    heightRito = h/2
} else {
    heightRito = widthRito/aspectRatio
}

// 归一化x值
function normalizationX(itemX){
    return (itemX - boundingBox[0])/boundingBoxWidth
}
// 归一化y值
function normalizationY(itemY){
    return (itemY - boundingBox[2])/boundingBoxHeight
}

屏幕坐标

将归一化坐标转换为屏幕坐标通常需要考虑两个因素:屏幕的尺寸和显示区域的大小。下面是一个基本的方法:

  • 确定屏幕尺寸和显示区域大小: 首先,需要知道屏幕的宽度和高度以及显示区域的宽度和高度,这些参数通常由设备或应用程序提供。

  • 计算缩放比例: 将归一化坐标转换成屏幕坐标时需要将其缩放到正确的比例。可以使用以下公式将归一化坐标缩放到指定的范围内:

x_screen = x_norm * display_width 
y_screen = y_norm * display_height

其中,x_norm和y_norm是归一化坐标,display_width和display_height是显示区域的宽度和高度。

调整坐标系: 在计算机图形学中,原点通常位于屏幕的左上角。如果你使用的是笛卡尔坐标系,则需要将y轴翻转以匹配屏幕坐标系。可以使用以下公式来完成此操作:

y_screen = display_height - y_screen

通过以上步骤,就可以将归一化坐标转换为屏幕坐标。

绘制

// 起点的x值
const startPointX = (normalizationX(points[0].x)*heightRito*aspectRatio)
// 起点的y值
const startPointY = (normalizationY(points[0].y)*heightRito)
// 绘制坐标
ctx.moveTo(startPointX + origin.x, h - origin.y);
points.map((item) => {
    ctx.lineTo(normalizationX(item.x)*heightRito*aspectRatio + origin.x,h - (origin.y + normalizationY(item.y)*heightRito - startPointY))
    ctx.fillStyle="black";
    if(item.y < 0) {
        ctx.fillText(item.num, normalizationX(item.x)*heightRito*aspectRatio + origin.x, h - (origin.y + normalizationY(item.y)*heightRito - startPointY) + 10);
    } else {
        ctx.fillText(item.num, normalizationX(item.x)*heightRito*aspectRatio + origin.x, h - (origin.y + normalizationY(item.y)*heightRito - startPointY) - 5);
    }
})
ctx.fillStyle="red";
ctx.fill();
ctx.closePath();
全部评论

相关推荐

09-09 20:45
已编辑
上海海洋大学 Java
点赞 评论 收藏
分享
litbisc:你先说会,然后去速成课自学一个月,出门在外,身份都是自己给的
点赞 评论 收藏
分享
呆呆头:不适合,就跑,不要有压力,别给自己压力
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务